From 6f7b6c816a170bb2cd6b9f33ce215d4d90ff2dcd Mon Sep 17 00:00:00 2001 From: Martin von Gagern Date: Fri, 12 Dec 2008 17:38:14 +0300 Subject: [PATCH 01/75] 5106550: PNG writer merge standard metadata fails for TextEntry sans #IMPLIED attributes Reviewed-by: igor, prr --- .../sun/imageio/plugins/png/PNGMetadata.java | 93 +++++++++++++------ .../plugins/png/MergeStdCommentTest.java | 64 +++++++++++++ 2 files changed, 131 insertions(+), 26 deletions(-) create mode 100644 jdk/test/javax/imageio/plugins/png/MergeStdCommentTest.java diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java b/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java index 5475fc79651..23281fe5330 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java @@ -1040,7 +1040,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { node.setAttribute("language", iTXt_languageTag.get(i)); if (iTXt_compressionFlag.get(i)) { - node.setAttribute("compression", "deflate"); + node.setAttribute("compression", "zip"); } else { node.setAttribute("compression", "none"); } @@ -1052,7 +1052,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { node = new IIOMetadataNode("TextEntry"); node.setAttribute("keyword", (String)zTXt_keyword.get(i)); node.setAttribute("value", (String)zTXt_text.get(i)); - node.setAttribute("compression", "deflate"); + node.setAttribute("compression", "zip"); text_node.appendChild(node); } @@ -1421,26 +1421,30 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { } String keyword = getAttribute(iTXt_node, "keyword"); - iTXt_keyword.add(keyword); + if (isValidKeyword(keyword)) { + iTXt_keyword.add(keyword); - boolean compressionFlag = - getBooleanAttribute(iTXt_node, "compressionFlag"); - iTXt_compressionFlag.add(Boolean.valueOf(compressionFlag)); + boolean compressionFlag = + getBooleanAttribute(iTXt_node, "compressionFlag"); + iTXt_compressionFlag.add(Boolean.valueOf(compressionFlag)); - String compressionMethod = - getAttribute(iTXt_node, "compressionMethod"); - iTXt_compressionMethod.add(Integer.valueOf(compressionMethod)); + String compressionMethod = + getAttribute(iTXt_node, "compressionMethod"); + iTXt_compressionMethod.add(Integer.valueOf(compressionMethod)); - String languageTag = - getAttribute(iTXt_node, "languageTag"); - iTXt_languageTag.add(languageTag); + String languageTag = + getAttribute(iTXt_node, "languageTag"); + iTXt_languageTag.add(languageTag); - String translatedKeyword = - getAttribute(iTXt_node, "translatedKeyword"); - iTXt_translatedKeyword.add(translatedKeyword); + String translatedKeyword = + getAttribute(iTXt_node, "translatedKeyword"); + iTXt_translatedKeyword.add(translatedKeyword); - String text = getAttribute(iTXt_node, "text"); - iTXt_text.add(text); + String text = getAttribute(iTXt_node, "text"); + iTXt_text.add(text); + + } + // silently skip invalid text entry iTXt_node = iTXt_node.getNextSibling(); } @@ -1692,11 +1696,45 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { } } - private boolean isISOLatin(String s) { + /* + * Accrding to PNG spec, keywords are restricted to 1 to 79 bytes + * in length. Keywords shall contain only printable Latin-1 characters + * and spaces; To reduce the chances for human misreading of a keyword, + * leading spaces, trailing spaces, and consecutive spaces are not + * permitted in keywords. + * + * See: http://www.w3.org/TR/PNG/#11keywords + */ + private boolean isValidKeyword(String s) { + int len = s.length(); + if (len < 1 || len >= 80) { + return false; + } + if (s.startsWith(" ") || s.endsWith(" ") || s.contains(" ")) { + return false; + } + return isISOLatin(s, false); + } + + /* + * According to PNG spec, keyword shall contain only printable + * Latin-1 [ISO-8859-1] characters and spaces; that is, only + * character codes 32-126 and 161-255 decimal are allowed. + * For Latin-1 value fields the 0x10 (linefeed) control + * character is aloowed too. + * + * See: http://www.w3.org/TR/PNG/#11keywords + */ + private boolean isISOLatin(String s, boolean isLineFeedAllowed) { int len = s.length(); for (int i = 0; i < len; i++) { - if (s.charAt(i) > 255) { - return false; + char c = s.charAt(i); + if (c < 32 || c > 255 || (c > 126 && c < 161)) { + // not printable. Check whether this is an allowed + // control char + if (!isLineFeedAllowed || c != 0x10) { + return false; + } } } return true; @@ -1929,19 +1967,22 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { while (child != null) { String childName = child.getNodeName(); if (childName.equals("TextEntry")) { - String keyword = getAttribute(child, "keyword"); + String keyword = + getAttribute(child, "keyword", "", false); String value = getAttribute(child, "value"); - String encoding = getAttribute(child, "encoding"); - String language = getAttribute(child, "language"); + String language = + getAttribute(child, "language", "", false); String compression = - getAttribute(child, "compression"); + getAttribute(child, "compression", "none", false); - if (isISOLatin(value)) { + if (!isValidKeyword(keyword)) { + // Just ignore this node, PNG requires keywords + } else if (isISOLatin(value, true)) { if (compression.equals("zip")) { // Use a zTXt node zTXt_keyword.add(keyword); zTXt_text.add(value); - zTXt_compressionMethod.add(new Integer(0)); + zTXt_compressionMethod.add(Integer.valueOf(0)); } else { // Use a tEXt node tEXt_keyword.add(keyword); diff --git a/jdk/test/javax/imageio/plugins/png/MergeStdCommentTest.java b/jdk/test/javax/imageio/plugins/png/MergeStdCommentTest.java new file mode 100644 index 00000000000..21a7c5f10d0 --- /dev/null +++ b/jdk/test/javax/imageio/plugins/png/MergeStdCommentTest.java @@ -0,0 +1,64 @@ +/* + * Copyright 2008 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 5106550 + * @summary Merge a comment using the standard metdata format + * and only a minimal set of attributes + */ + +import java.awt.image.BufferedImage; +import javax.imageio.ImageIO; +import javax.imageio.ImageTypeSpecifier; +import javax.imageio.ImageWriter; +import javax.imageio.metadata.IIOMetadata; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.bootstrap.DOMImplementationRegistry; + +public class MergeStdCommentTest { + + public static void main(String[] args) throws Exception { + String format = "javax_imageio_1.0"; + BufferedImage img = + new BufferedImage(16, 16, BufferedImage.TYPE_INT_RGB); + ImageWriter iw = ImageIO.getImageWritersByMIMEType("image/png").next(); + IIOMetadata meta = + iw.getDefaultImageMetadata(new ImageTypeSpecifier(img), null); + DOMImplementationRegistry registry; + registry = DOMImplementationRegistry.newInstance(); + DOMImplementation impl = registry.getDOMImplementation("XML 3.0"); + Document doc = impl.createDocument(null, format, null); + Element root, text, entry; + root = doc.getDocumentElement(); + root.appendChild(text = doc.createElement("Text")); + text.appendChild(entry = doc.createElement("TextEntry")); + // keyword isn't #REQUIRED by the standard metadata format. + // However, it is required by the PNG format, so we include it here. + entry.setAttribute("keyword", "Comment"); + entry.setAttribute("value", "Some demo comment"); + meta.mergeTree(format, root); + } +} From 8848b3ab632432de85c70173dc26a4bdc2790479 Mon Sep 17 00:00:00 2001 From: Igor Nekrestyanov Date: Wed, 17 Dec 2008 22:00:37 +0300 Subject: [PATCH 02/75] 6761791: Crash in the FontManager code due to use of JNIEnv saved by another thread Reviewed-by: bae, prr --- .../share/native/sun/font/freetypeScaler.c | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/jdk/src/share/native/sun/font/freetypeScaler.c b/jdk/src/share/native/sun/font/freetypeScaler.c index 59c1a180c29..4028d4d97c4 100644 --- a/jdk/src/share/native/sun/font/freetypeScaler.c +++ b/jdk/src/share/native/sun/font/freetypeScaler.c @@ -394,12 +394,14 @@ static int setupFTContext(JNIEnv *env, scalerInfo->env = env; scalerInfo->font2D = font2D; - FT_Set_Transform(scalerInfo->face, &context->transform, NULL); + if (context != NULL) { + FT_Set_Transform(scalerInfo->face, &context->transform, NULL); - errCode = FT_Set_Char_Size(scalerInfo->face, 0, context->ptsz, 72, 72); + errCode = FT_Set_Char_Size(scalerInfo->face, 0, context->ptsz, 72, 72); - if (errCode == 0) { - errCode = FT_Activate_Size(scalerInfo->face->size); + if (errCode == 0) { + errCode = FT_Activate_Size(scalerInfo->face->size); + } } return errCode; @@ -885,6 +887,14 @@ Java_sun_font_FreetypeFontScaler_disposeNativeScaler( JNIEnv *env, jobject scaler, jlong pScaler) { FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler); + /* Freetype functions *may* cause callback to java + that can use cached values. Make sure our cache is up to date. + NB: scaler context is not important at this point, can use NULL. */ + int errCode = setupFTContext(env, scaler, scalerInfo, NULL); + if (errCode) { + return; + } + freeNativeResources(env, scalerInfo); } @@ -932,12 +942,21 @@ Java_sun_font_FreetypeFontScaler_getGlyphCodeNative( JNIEnv *env, jobject scaler, jlong pScaler, jchar charCode) { FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler); + int errCode; if (scaler == NULL || scalerInfo->face == NULL) { /* bad/null scaler */ invalidateJavaScaler(env, scaler, scalerInfo); return 0; } + /* Freetype functions *may* cause callback to java + that can use cached values. Make sure our cache is up to date. + Scaler context is not important here, can use NULL. */ + errCode = setupFTContext(env, scaler, scalerInfo, NULL); + if (errCode) { + return 0; + } + return FT_Get_Char_Index(scalerInfo->face, charCode); } From 5b1de891b340083d3bc451e8c56c318634193994 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Thu, 18 Dec 2008 11:25:09 -0800 Subject: [PATCH 03/75] 6708137: Remove obsolete fontconfig.98.properties from JDK 7 Reviewed-by: jgodinez, naoto --- jdk/make/sun/awt/Makefile | 3 +- .../sun/awt/windows/WFontConfiguration.java | 16 +- .../sun/awt/windows/fontconfig.98.properties | 241 ------------------ .../sun/awt/windows/fontconfig.Me.properties | 241 ------------------ 4 files changed, 5 insertions(+), 496 deletions(-) delete mode 100644 jdk/src/windows/classes/sun/awt/windows/fontconfig.98.properties delete mode 100644 jdk/src/windows/classes/sun/awt/windows/fontconfig.Me.properties diff --git a/jdk/make/sun/awt/Makefile b/jdk/make/sun/awt/Makefile index ed35dcd2bdf..3f9fa64eb11 100644 --- a/jdk/make/sun/awt/Makefile +++ b/jdk/make/sun/awt/Makefile @@ -333,8 +333,7 @@ ifeq ($(PLATFORM), windows) FONTCONFIGS_SRC = $(PLATFORM_SRC)/classes/sun/awt/windows _FONTCONFIGS = \ - fontconfig.properties \ - fontconfig.98.properties + fontconfig.properties FONTCONFIGS_SRC_PREFIX = diff --git a/jdk/src/windows/classes/sun/awt/windows/WFontConfiguration.java b/jdk/src/windows/classes/sun/awt/windows/WFontConfiguration.java index 4f2f8324ae4..2c7b00124a7 100644 --- a/jdk/src/windows/classes/sun/awt/windows/WFontConfiguration.java +++ b/jdk/src/windows/classes/sun/awt/windows/WFontConfiguration.java @@ -61,18 +61,10 @@ public class WFontConfiguration extends FontConfiguration { * been opened and its fonts loaded. * Also note this usage is only enabled if a private flag is set. */ - if ("98".equals(osName) || "Me".equals(osName)) { - localeMap.put("dialoginput.plain.japanese", "\uff2d\uff33 \u660e\u671d"); - localeMap.put("dialoginput.bold.japanese", "\uff2d\uff33 \u660e\u671d"); - localeMap.put("dialoginput.italic.japanese", "\uff2d\uff33 \u660e\u671d"); - localeMap.put("dialoginput.bolditalic.japanese", "\uff2d\uff33 \u660e\u671d"); - } else { - - localeMap.put("dialoginput.plain.japanese", "MS Mincho"); - localeMap.put("dialoginput.bold.japanese", "MS Mincho"); - localeMap.put("dialoginput.italic.japanese", "MS Mincho"); - localeMap.put("dialoginput.bolditalic.japanese", "MS Mincho"); - } + localeMap.put("dialoginput.plain.japanese", "MS Mincho"); + localeMap.put("dialoginput.bold.japanese", "MS Mincho"); + localeMap.put("dialoginput.italic.japanese", "MS Mincho"); + localeMap.put("dialoginput.bolditalic.japanese", "MS Mincho"); } reorderMap = new HashMap(); reorderMap.put("UTF-8.hi", "devanagari"); diff --git a/jdk/src/windows/classes/sun/awt/windows/fontconfig.98.properties b/jdk/src/windows/classes/sun/awt/windows/fontconfig.98.properties deleted file mode 100644 index 8d69d410e25..00000000000 --- a/jdk/src/windows/classes/sun/awt/windows/fontconfig.98.properties +++ /dev/null @@ -1,241 +0,0 @@ -# -# -# Copyright 2003-2004 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. Sun designates this -# particular file as subject to the "Classpath" exception as provided -# by Sun in the LICENSE file that accompanied this code. -# -# 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. -# - -# Version - -version=1 - -# Component Font Mappings - -allfonts.chinese-ms936=SimSun -allfonts.dingbats=Wingdings -allfonts.lucida=Lucida Sans Regular -allfonts.symbol=Symbol -allfonts.thai=Lucida Sans Regular - -serif.plain.alphabetic=Times New Roman -serif.plain.chinese-ms950=MingLiU -serif.plain.hebrew=David -serif.plain.japanese=\uff2d\uff33 \u660e\u671d -serif.plain.korean=Batang - -serif.bold.alphabetic=Times New Roman Bold -serif.bold.chinese-ms950=PMingLiU -serif.bold.hebrew=David Bold -serif.bold.japanese=\uff2d\uff33 \u660e\u671d -serif.bold.korean=Batang - -serif.italic.alphabetic=Times New Roman Italic -serif.italic.chinese-ms950=PMingLiU -serif.italic.hebrew=David -serif.italic.japanese=\uff2d\uff33 \u660e\u671d -serif.italic.korean=Batang - -serif.bolditalic.alphabetic=Times New Roman Bold Italic -serif.bolditalic.chinese-ms950=PMingLiU -serif.bolditalic.hebrew=David Bold -serif.bolditalic.japanese=\uff2d\uff33 \u660e\u671d -serif.bolditalic.korean=Batang - -sansserif.plain.alphabetic=Arial -sansserif.plain.chinese-ms950=MingLiU -sansserif.plain.hebrew=David -sansserif.plain.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -sansserif.plain.korean=Gulim - -sansserif.bold.alphabetic=Arial Bold -sansserif.bold.chinese-ms950=PMingLiU -sansserif.bold.hebrew=David Bold -sansserif.bold.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -sansserif.bold.korean=Gulim - -sansserif.italic.alphabetic=Arial Italic -sansserif.italic.chinese-ms950=PMingLiU -sansserif.italic.hebrew=David -sansserif.italic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -sansserif.italic.korean=Gulim - -sansserif.bolditalic.alphabetic=Arial Bold Italic -sansserif.bolditalic.chinese-ms950=PMingLiU -sansserif.bolditalic.hebrew=David Bold -sansserif.bolditalic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -sansserif.bolditalic.korean=Gulim - -monospaced.plain.alphabetic=Courier New -monospaced.plain.chinese-ms950=MingLiU -monospaced.plain.hebrew=David -monospaced.plain.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -monospaced.plain.korean=GulimChe - -monospaced.bold.alphabetic=Courier New Bold -monospaced.bold.chinese-ms950=PMingLiU -monospaced.bold.hebrew=David Bold -monospaced.bold.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -monospaced.bold.korean=GulimChe - -monospaced.italic.alphabetic=Courier New Italic -monospaced.italic.chinese-ms950=PMingLiU -monospaced.italic.hebrew=David -monospaced.italic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -monospaced.italic.korean=GulimChe - -monospaced.bolditalic.alphabetic=Courier New Bold Italic -monospaced.bolditalic.chinese-ms950=PMingLiU -monospaced.bolditalic.hebrew=David Bold -monospaced.bolditalic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -monospaced.bolditalic.korean=GulimChe - -dialog.plain.alphabetic=Arial -dialog.plain.chinese-ms950=MingLiU -dialog.plain.hebrew=David -dialog.plain.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialog.plain.korean=Gulim - -dialog.bold.alphabetic=Arial Bold -dialog.bold.chinese-ms950=PMingLiU -dialog.bold.hebrew=David Bold -dialog.bold.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialog.bold.korean=Gulim - -dialog.italic.alphabetic=Arial Italic -dialog.italic.chinese-ms950=PMingLiU -dialog.italic.hebrew=David -dialog.italic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialog.italic.korean=Gulim - -dialog.bolditalic.alphabetic=Arial Bold Italic -dialog.bolditalic.chinese-ms950=PMingLiU -dialog.bolditalic.hebrew=David Bold -dialog.bolditalic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialog.bolditalic.korean=Gulim - -dialoginput.plain.alphabetic=Courier New -dialoginput.plain.chinese-ms950=MingLiU -dialoginput.plain.hebrew=David -dialoginput.plain.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialoginput.plain.korean=Gulim - -dialoginput.bold.alphabetic=Courier New Bold -dialoginput.bold.chinese-ms950=PMingLiU -dialoginput.bold.hebrew=David Bold -dialoginput.bold.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialoginput.bold.korean=Gulim - -dialoginput.italic.alphabetic=Courier New Italic -dialoginput.italic.chinese-ms950=PMingLiU -dialoginput.italic.hebrew=David -dialoginput.italic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialoginput.italic.korean=Gulim - -dialoginput.bolditalic.alphabetic=Courier New Bold Italic -dialoginput.bolditalic.chinese-ms950=PMingLiU -dialoginput.bolditalic.hebrew=David Bold -dialoginput.bolditalic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialoginput.bolditalic.korean=Gulim - -# Search Sequences - -sequence.allfonts=alphabetic/default,dingbats,symbol - -sequence.serif.GBK=alphabetic/1252,chinese-ms936,dingbats,symbol -sequence.sansserif.GBK=alphabetic/1252,chinese-ms936,dingbats,symbol -sequence.monospaced.GBK=chinese-ms936,alphabetic/1252,dingbats,symbol -sequence.dialog.GBK=alphabetic/1252,chinese-ms936,dingbats,symbol -sequence.dialoginput.GBK=alphabetic/1252,chinese-ms936,dingbats,symbol - -sequence.serif.x-windows-950=alphabetic/1252,chinese-ms950,dingbats,symbol -sequence.sansserif.x-windows-950=alphabetic/1252,chinese-ms950,dingbats,symbol -sequence.monospaced.x-windows-950=chinese-ms950,alphabetic/1252,dingbats,symbol -sequence.dialog.x-windows-950=alphabetic/1252,chinese-ms950,dingbats,symbol -sequence.dialoginput.x-windows-950=alphabetic/1252,chinese-ms950,dingbats,symbol - -sequence.allfonts.windows-1255=hebrew,alphabetic/1252,dingbats,symbol - -sequence.serif.windows-31j=alphabetic/1252,japanese,dingbats,symbol -sequence.sansserif.windows-31j=alphabetic/1252,japanese,dingbats,symbol -sequence.monospaced.windows-31j=japanese,alphabetic/1252,dingbats,symbol -sequence.dialog.windows-31j=alphabetic/1252,japanese,dingbats,symbol -sequence.dialoginput.windows-31j=alphabetic/1252,japanese,dingbats,symbol - -sequence.serif.x-windows-949=alphabetic/1252,korean,dingbats,symbol -sequence.sansserif.x-windows-949=alphabetic/1252,korean,dingbats,symbol -sequence.monospaced.x-windows-949=korean,alphabetic/1252,dingbats,symbol -sequence.dialog.x-windows-949=alphabetic/1252,korean,dingbats,symbol -sequence.dialoginput.x-windows-949=alphabetic/1252,korean,dingbats,symbol - -sequence.allfonts.x-windows-874=alphabetic/1252,thai,dingbats,symbol - -sequence.fallback=lucida - -# Exclusion Ranges - -exclusion.alphabetic=0700-1e9f,1f00-20ab,20ad-f8ff -exclusion.hebrew=0041-005a,0060-007a,007f-00ff,20ac-20ac - -# Monospaced to Proportional width variant mapping -# (Experimental private syntax) -proportional.\uff2d\uff33_\u30b4\u30b7\u30c3\u30af=\uff2d\uff33 \uff30\u30b4\u30b7\u30c3\u30af -proportional.\uff2d\uff33_\u660e\u671d=\uff2d\uff33 \uff30\u660e\u671d -proportional.MingLiU=PMingLiU - -# Font File Names - -filename.Arial=ARIAL.TTF -filename.Arial_Bold=ARIALBD.TTF -filename.Arial_Italic=ARIALI.TTF -filename.Arial_Bold_Italic=ARIALBI.TTF - -filename.Courier_New=COUR.TTF -filename.Courier_New_Bold=COURBD.TTF -filename.Courier_New_Italic=COURI.TTF -filename.Courier_New_Bold_Italic=COURBI.TTF - -filename.Times_New_Roman=TIMES.TTF -filename.Times_New_Roman_Bold=TIMESBD.TTF -filename.Times_New_Roman_Italic=TIMESI.TTF -filename.Times_New_Roman_Bold_Italic=TIMESBI.TTF - -filename.SimSun=SIMSUN.TTF - -filename.MingLiU=MINGLIU.TTC -filename.PMingLiU=MINGLIU.TTC - -filename.David=DAVID.TTF -filename.David_Bold=DAVIDBD.TTF - -filename.\uff2d\uff33_\u660e\u671d=MSMINCHO.TTC -filename.\uff2d\uff33_\uff30\u660e\u671d=MSMINCHO.TTC -filename.\uff2d\uff33_\u30b4\u30b7\u30c3\u30af=MSGOTHIC.TTC -filename.\uff2d\uff33_\uff30\u30b4\u30b7\u30c3\u30af=MSGOTHIC.TTC - -filename.Gulim=gulim.TTC -filename.Batang=batang.TTC -filename.GulimChe=gulim.TTC - -filename.Lucida_Sans_Regular=LucidaSansRegular.ttf -filename.Symbol=SYMBOL.TTF -filename.Wingdings=WINGDING.TTF - diff --git a/jdk/src/windows/classes/sun/awt/windows/fontconfig.Me.properties b/jdk/src/windows/classes/sun/awt/windows/fontconfig.Me.properties deleted file mode 100644 index 8d69d410e25..00000000000 --- a/jdk/src/windows/classes/sun/awt/windows/fontconfig.Me.properties +++ /dev/null @@ -1,241 +0,0 @@ -# -# -# Copyright 2003-2004 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. Sun designates this -# particular file as subject to the "Classpath" exception as provided -# by Sun in the LICENSE file that accompanied this code. -# -# 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. -# - -# Version - -version=1 - -# Component Font Mappings - -allfonts.chinese-ms936=SimSun -allfonts.dingbats=Wingdings -allfonts.lucida=Lucida Sans Regular -allfonts.symbol=Symbol -allfonts.thai=Lucida Sans Regular - -serif.plain.alphabetic=Times New Roman -serif.plain.chinese-ms950=MingLiU -serif.plain.hebrew=David -serif.plain.japanese=\uff2d\uff33 \u660e\u671d -serif.plain.korean=Batang - -serif.bold.alphabetic=Times New Roman Bold -serif.bold.chinese-ms950=PMingLiU -serif.bold.hebrew=David Bold -serif.bold.japanese=\uff2d\uff33 \u660e\u671d -serif.bold.korean=Batang - -serif.italic.alphabetic=Times New Roman Italic -serif.italic.chinese-ms950=PMingLiU -serif.italic.hebrew=David -serif.italic.japanese=\uff2d\uff33 \u660e\u671d -serif.italic.korean=Batang - -serif.bolditalic.alphabetic=Times New Roman Bold Italic -serif.bolditalic.chinese-ms950=PMingLiU -serif.bolditalic.hebrew=David Bold -serif.bolditalic.japanese=\uff2d\uff33 \u660e\u671d -serif.bolditalic.korean=Batang - -sansserif.plain.alphabetic=Arial -sansserif.plain.chinese-ms950=MingLiU -sansserif.plain.hebrew=David -sansserif.plain.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -sansserif.plain.korean=Gulim - -sansserif.bold.alphabetic=Arial Bold -sansserif.bold.chinese-ms950=PMingLiU -sansserif.bold.hebrew=David Bold -sansserif.bold.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -sansserif.bold.korean=Gulim - -sansserif.italic.alphabetic=Arial Italic -sansserif.italic.chinese-ms950=PMingLiU -sansserif.italic.hebrew=David -sansserif.italic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -sansserif.italic.korean=Gulim - -sansserif.bolditalic.alphabetic=Arial Bold Italic -sansserif.bolditalic.chinese-ms950=PMingLiU -sansserif.bolditalic.hebrew=David Bold -sansserif.bolditalic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -sansserif.bolditalic.korean=Gulim - -monospaced.plain.alphabetic=Courier New -monospaced.plain.chinese-ms950=MingLiU -monospaced.plain.hebrew=David -monospaced.plain.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -monospaced.plain.korean=GulimChe - -monospaced.bold.alphabetic=Courier New Bold -monospaced.bold.chinese-ms950=PMingLiU -monospaced.bold.hebrew=David Bold -monospaced.bold.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -monospaced.bold.korean=GulimChe - -monospaced.italic.alphabetic=Courier New Italic -monospaced.italic.chinese-ms950=PMingLiU -monospaced.italic.hebrew=David -monospaced.italic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -monospaced.italic.korean=GulimChe - -monospaced.bolditalic.alphabetic=Courier New Bold Italic -monospaced.bolditalic.chinese-ms950=PMingLiU -monospaced.bolditalic.hebrew=David Bold -monospaced.bolditalic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -monospaced.bolditalic.korean=GulimChe - -dialog.plain.alphabetic=Arial -dialog.plain.chinese-ms950=MingLiU -dialog.plain.hebrew=David -dialog.plain.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialog.plain.korean=Gulim - -dialog.bold.alphabetic=Arial Bold -dialog.bold.chinese-ms950=PMingLiU -dialog.bold.hebrew=David Bold -dialog.bold.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialog.bold.korean=Gulim - -dialog.italic.alphabetic=Arial Italic -dialog.italic.chinese-ms950=PMingLiU -dialog.italic.hebrew=David -dialog.italic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialog.italic.korean=Gulim - -dialog.bolditalic.alphabetic=Arial Bold Italic -dialog.bolditalic.chinese-ms950=PMingLiU -dialog.bolditalic.hebrew=David Bold -dialog.bolditalic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialog.bolditalic.korean=Gulim - -dialoginput.plain.alphabetic=Courier New -dialoginput.plain.chinese-ms950=MingLiU -dialoginput.plain.hebrew=David -dialoginput.plain.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialoginput.plain.korean=Gulim - -dialoginput.bold.alphabetic=Courier New Bold -dialoginput.bold.chinese-ms950=PMingLiU -dialoginput.bold.hebrew=David Bold -dialoginput.bold.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialoginput.bold.korean=Gulim - -dialoginput.italic.alphabetic=Courier New Italic -dialoginput.italic.chinese-ms950=PMingLiU -dialoginput.italic.hebrew=David -dialoginput.italic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialoginput.italic.korean=Gulim - -dialoginput.bolditalic.alphabetic=Courier New Bold Italic -dialoginput.bolditalic.chinese-ms950=PMingLiU -dialoginput.bolditalic.hebrew=David Bold -dialoginput.bolditalic.japanese=\uff2d\uff33 \u30b4\u30b7\u30c3\u30af -dialoginput.bolditalic.korean=Gulim - -# Search Sequences - -sequence.allfonts=alphabetic/default,dingbats,symbol - -sequence.serif.GBK=alphabetic/1252,chinese-ms936,dingbats,symbol -sequence.sansserif.GBK=alphabetic/1252,chinese-ms936,dingbats,symbol -sequence.monospaced.GBK=chinese-ms936,alphabetic/1252,dingbats,symbol -sequence.dialog.GBK=alphabetic/1252,chinese-ms936,dingbats,symbol -sequence.dialoginput.GBK=alphabetic/1252,chinese-ms936,dingbats,symbol - -sequence.serif.x-windows-950=alphabetic/1252,chinese-ms950,dingbats,symbol -sequence.sansserif.x-windows-950=alphabetic/1252,chinese-ms950,dingbats,symbol -sequence.monospaced.x-windows-950=chinese-ms950,alphabetic/1252,dingbats,symbol -sequence.dialog.x-windows-950=alphabetic/1252,chinese-ms950,dingbats,symbol -sequence.dialoginput.x-windows-950=alphabetic/1252,chinese-ms950,dingbats,symbol - -sequence.allfonts.windows-1255=hebrew,alphabetic/1252,dingbats,symbol - -sequence.serif.windows-31j=alphabetic/1252,japanese,dingbats,symbol -sequence.sansserif.windows-31j=alphabetic/1252,japanese,dingbats,symbol -sequence.monospaced.windows-31j=japanese,alphabetic/1252,dingbats,symbol -sequence.dialog.windows-31j=alphabetic/1252,japanese,dingbats,symbol -sequence.dialoginput.windows-31j=alphabetic/1252,japanese,dingbats,symbol - -sequence.serif.x-windows-949=alphabetic/1252,korean,dingbats,symbol -sequence.sansserif.x-windows-949=alphabetic/1252,korean,dingbats,symbol -sequence.monospaced.x-windows-949=korean,alphabetic/1252,dingbats,symbol -sequence.dialog.x-windows-949=alphabetic/1252,korean,dingbats,symbol -sequence.dialoginput.x-windows-949=alphabetic/1252,korean,dingbats,symbol - -sequence.allfonts.x-windows-874=alphabetic/1252,thai,dingbats,symbol - -sequence.fallback=lucida - -# Exclusion Ranges - -exclusion.alphabetic=0700-1e9f,1f00-20ab,20ad-f8ff -exclusion.hebrew=0041-005a,0060-007a,007f-00ff,20ac-20ac - -# Monospaced to Proportional width variant mapping -# (Experimental private syntax) -proportional.\uff2d\uff33_\u30b4\u30b7\u30c3\u30af=\uff2d\uff33 \uff30\u30b4\u30b7\u30c3\u30af -proportional.\uff2d\uff33_\u660e\u671d=\uff2d\uff33 \uff30\u660e\u671d -proportional.MingLiU=PMingLiU - -# Font File Names - -filename.Arial=ARIAL.TTF -filename.Arial_Bold=ARIALBD.TTF -filename.Arial_Italic=ARIALI.TTF -filename.Arial_Bold_Italic=ARIALBI.TTF - -filename.Courier_New=COUR.TTF -filename.Courier_New_Bold=COURBD.TTF -filename.Courier_New_Italic=COURI.TTF -filename.Courier_New_Bold_Italic=COURBI.TTF - -filename.Times_New_Roman=TIMES.TTF -filename.Times_New_Roman_Bold=TIMESBD.TTF -filename.Times_New_Roman_Italic=TIMESI.TTF -filename.Times_New_Roman_Bold_Italic=TIMESBI.TTF - -filename.SimSun=SIMSUN.TTF - -filename.MingLiU=MINGLIU.TTC -filename.PMingLiU=MINGLIU.TTC - -filename.David=DAVID.TTF -filename.David_Bold=DAVIDBD.TTF - -filename.\uff2d\uff33_\u660e\u671d=MSMINCHO.TTC -filename.\uff2d\uff33_\uff30\u660e\u671d=MSMINCHO.TTC -filename.\uff2d\uff33_\u30b4\u30b7\u30c3\u30af=MSGOTHIC.TTC -filename.\uff2d\uff33_\uff30\u30b4\u30b7\u30c3\u30af=MSGOTHIC.TTC - -filename.Gulim=gulim.TTC -filename.Batang=batang.TTC -filename.GulimChe=gulim.TTC - -filename.Lucida_Sans_Regular=LucidaSansRegular.ttf -filename.Symbol=SYMBOL.TTF -filename.Wingdings=WINGDING.TTF - From fa5248c9db8c661b898ff4e9e03433128b2534c4 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Wed, 24 Dec 2008 09:53:52 -0800 Subject: [PATCH 04/75] 6728838: Native memory leak in StrikeCache.java Reviewed-by: bae, igor --- jdk/src/share/classes/sun/font/StrikeCache.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/jdk/src/share/classes/sun/font/StrikeCache.java b/jdk/src/share/classes/sun/font/StrikeCache.java index 560be3af2cd..56539e7489f 100644 --- a/jdk/src/share/classes/sun/font/StrikeCache.java +++ b/jdk/src/share/classes/sun/font/StrikeCache.java @@ -232,6 +232,16 @@ public final class StrikeCache { if (disposer.pScalerContext != 0L) { freeLongMemory(new long[0], disposer.pScalerContext); } + } else if (disposer.pScalerContext != 0L) { + /* Rarely a strike may have been created that never cached + * any glyphs. In this case we still want to free the scaler + * context. + */ + if (FontManager.longAddresses) { + freeLongMemory(new long[0], disposer.pScalerContext); + } else { + freeIntMemory(new int[0], disposer.pScalerContext); + } } } From 6f0de04c8704af289dcfa836939be14c9dc0a365 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Wed, 24 Dec 2008 09:57:48 -0800 Subject: [PATCH 05/75] 6752638: java.awt.GraphicsEnvironment.preferLocaleFonts() throws NPE on Linux 6755034: Legal notice repair: jdk/src/solaris/classes/sun/font/FcFontConfiguration.java Reviewed-by: bae, igor --- .../classes/java/awt/GraphicsEnvironment.java | 6 ++ .../classes/sun/awt/FontConfiguration.java | 6 +- .../classes/sun/font/FcFontConfiguration.java | 3 +- .../PreferLocaleFonts.java | 62 +++++++++++++++++++ 4 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 jdk/test/java/awt/GraphicsEnvironment/PreferLocaleFonts.java diff --git a/jdk/src/share/classes/java/awt/GraphicsEnvironment.java b/jdk/src/share/classes/java/awt/GraphicsEnvironment.java index 167db051910..cf1852e2fc0 100644 --- a/jdk/src/share/classes/java/awt/GraphicsEnvironment.java +++ b/jdk/src/share/classes/java/awt/GraphicsEnvironment.java @@ -356,6 +356,9 @@ public abstract class GraphicsEnvironment { * @since 1.5 */ public void preferLocaleFonts() { + if (!(this instanceof SunGraphicsEnvironment)) { + return; + } sun.font.FontManager.preferLocaleFonts(); } @@ -376,6 +379,9 @@ public abstract class GraphicsEnvironment { * @since 1.5 */ public void preferProportionalFonts() { + if (!(this instanceof SunGraphicsEnvironment)) { + return; + } sun.font.FontManager.preferProportionalFonts(); } diff --git a/jdk/src/share/classes/sun/awt/FontConfiguration.java b/jdk/src/share/classes/sun/awt/FontConfiguration.java index 6349aa778ea..4504af24e9d 100644 --- a/jdk/src/share/classes/sun/awt/FontConfiguration.java +++ b/jdk/src/share/classes/sun/awt/FontConfiguration.java @@ -98,7 +98,7 @@ public abstract class FontConfiguration { if (!inited) { this.preferLocaleFonts = false; this.preferPropFonts = false; - fontConfig = this; /* static initialization */ + setFontConfiguration(); readFontConfigFile(fontConfigFile); initFontConfig(); inited = true; @@ -1244,6 +1244,10 @@ public abstract class FontConfiguration { return fontConfig; } + protected void setFontConfiguration() { + fontConfig = this; /* static initialization */ + } + ////////////////////////////////////////////////////////////////////// // FontConfig data tables and the index constants in binary file // ////////////////////////////////////////////////////////////////////// diff --git a/jdk/src/solaris/classes/sun/font/FcFontConfiguration.java b/jdk/src/solaris/classes/sun/font/FcFontConfiguration.java index fe2e5dbf836..95154df0a47 100644 --- a/jdk/src/solaris/classes/sun/font/FcFontConfiguration.java +++ b/jdk/src/solaris/classes/sun/font/FcFontConfiguration.java @@ -15,7 +15,7 @@ * accompanied this code). * * You should have received a copy of the GNU General Public License version - * along with this work; if not, write to the Free Software Foundation, + * 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, @@ -87,6 +87,7 @@ public class FcFontConfiguration extends FontConfiguration { return true; } + setFontConfiguration(); readFcInfo(); if (fcCompFonts == null) { fcCompFonts = FontManager.loadFontConfig(); diff --git a/jdk/test/java/awt/GraphicsEnvironment/PreferLocaleFonts.java b/jdk/test/java/awt/GraphicsEnvironment/PreferLocaleFonts.java new file mode 100644 index 00000000000..3d8cb5934f5 --- /dev/null +++ b/jdk/test/java/awt/GraphicsEnvironment/PreferLocaleFonts.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2008 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 6752638 + * @summary Test no NPE calling preferLocaleFonts() on custom GE. + * @run main PreferLocaleFonts + */ + +import java.util.*; +import java.awt.*; +import java.awt.image.*; + +public class PreferLocaleFonts extends GraphicsEnvironment { + + public static void main(String args[]) { +(new PreferLocaleFonts()).preferLocaleFonts(); + } + public PreferLocaleFonts() { + super(); + } + public Graphics2D createGraphics(BufferedImage image) { + return null; + } + public String[] getAvailableFontFamilyNames(Locale locale) { + return null; + } + public String[] getAvailableFontFamilyNames() { + return null; + } + public Font[] getAllFonts() { + return null; + } + public GraphicsDevice getDefaultScreenDevice() throws HeadlessException { + return null; + } + public GraphicsDevice[] getScreenDevices() throws HeadlessException { + return null; + } +} + From a0930ff4d46ce23e6b298e862857768afd6d9d15 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Tue, 6 Jan 2009 13:52:03 -0800 Subject: [PATCH 06/75] 6785424: SecurityException locating physical fonts on Windows Terminal Server Reviewed-by: campbell, jgodinez --- .../share/classes/sun/font/FontManager.java | 21 +++++--- jdk/test/java/awt/FontClass/FontAccess.java | 48 +++++++++++++++++++ 2 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 jdk/test/java/awt/FontClass/FontAccess.java diff --git a/jdk/src/share/classes/sun/font/FontManager.java b/jdk/src/share/classes/sun/font/FontManager.java index f709f381ada..a8b721daffc 100644 --- a/jdk/src/share/classes/sun/font/FontManager.java +++ b/jdk/src/share/classes/sun/font/FontManager.java @@ -1601,18 +1601,27 @@ public final class FontManager { /* Path may be absolute or a base file name relative to one of * the platform font directories */ - private static String getPathName(String s) { + private static String getPathName(final String s) { File f = new File(s); if (f.isAbsolute()) { return s; } else if (pathDirs.length==1) { return pathDirs[0] + File.separator + s; } else { - for (int p=0; p() { + public String run() { + for (int p=0; p Date: Mon, 12 Jan 2009 16:02:47 -0800 Subject: [PATCH 07/75] 6752622: java.awt.Font.getPeer throws "java.lang.InternalError: Not implemented" on Linux Reviewed-by: igor, yan --- jdk/src/solaris/classes/sun/awt/X11/XFontPeer.java | 7 ------- jdk/src/solaris/classes/sun/font/FcFontConfiguration.java | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/jdk/src/solaris/classes/sun/awt/X11/XFontPeer.java b/jdk/src/solaris/classes/sun/awt/X11/XFontPeer.java index 62044ace53e..3d03a2503aa 100644 --- a/jdk/src/solaris/classes/sun/awt/X11/XFontPeer.java +++ b/jdk/src/solaris/classes/sun/awt/X11/XFontPeer.java @@ -27,9 +27,6 @@ package sun.awt.X11; import sun.awt.PlatformFont; import java.awt.GraphicsEnvironment; -/* FIX ME */ -import sun.awt.motif.MFontConfiguration; - public class XFontPeer extends PlatformFont { /* @@ -51,10 +48,6 @@ public class XFontPeer extends PlatformFont { public XFontPeer(String name, int style){ super(name, style); - - if (fontConfig != null){ - xfsname = ((MFontConfiguration) fontConfig).getMotifFontSet(familyName, style); - } } protected char getMissingGlyphCharacter() { diff --git a/jdk/src/solaris/classes/sun/font/FcFontConfiguration.java b/jdk/src/solaris/classes/sun/font/FcFontConfiguration.java index 95154df0a47..a34fed02e15 100644 --- a/jdk/src/solaris/classes/sun/font/FcFontConfiguration.java +++ b/jdk/src/solaris/classes/sun/font/FcFontConfiguration.java @@ -173,7 +173,7 @@ public class FcFontConfiguration extends FontConfiguration { @Override public FontDescriptor[] getFontDescriptors(String fontName, int style) { - throw new InternalError("Not implemented"); + return new FontDescriptor[0]; } @Override From bf4d190698d0b36f90af28f05ef856b7d03ffd52 Mon Sep 17 00:00:00 2001 From: Martin von Gagern Date: Tue, 13 Jan 2009 16:55:12 +0300 Subject: [PATCH 08/75] 5082756: Image I/O plug-ins set metadata boolean attributes to "true" or "false" Reviewed-by: igor, prr --- .../imageio/plugins/gif/GIFImageMetadata.java | 6 +- .../sun/imageio/plugins/gif/GIFMetadata.java | 9 +- .../plugins/gif/GIFStreamMetadata.java | 2 +- .../imageio/plugins/jpeg/JPEGMetadata.java | 2 +- .../sun/imageio/plugins/png/PNGMetadata.java | 13 +- .../imageio/metadata/IIOMetadataFormat.java | 8 +- .../imageio/metadata/BooleanAttributes.java | 202 ++++++++++++++++++ .../javax/imageio/plugins/png/ITXtTest.java | 2 +- 8 files changed, 224 insertions(+), 20 deletions(-) create mode 100644 jdk/test/javax/imageio/metadata/BooleanAttributes.java diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadata.java b/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadata.java index 08da84856b7..9660d82603a 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadata.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadata.java @@ -153,7 +153,7 @@ public class GIFImageMetadata extends GIFMetadata { node.setAttribute("imageWidth", Integer.toString(imageWidth)); node.setAttribute("imageHeight", Integer.toString(imageHeight)); node.setAttribute("interlaceFlag", - interlaceFlag ? "true" : "false"); + interlaceFlag ? "TRUE" : "FALSE"); root.appendChild(node); // Local color table @@ -185,9 +185,9 @@ public class GIFImageMetadata extends GIFMetadata { node.setAttribute("disposalMethod", disposalMethodNames[disposalMethod]); node.setAttribute("userInputFlag", - userInputFlag ? "true" : "false"); + userInputFlag ? "TRUE" : "FALSE"); node.setAttribute("transparentColorFlag", - transparentColorFlag ? "true" : "false"); + transparentColorFlag ? "TRUE" : "FALSE"); node.setAttribute("delayTime", Integer.toString(delayTime)); node.setAttribute("transparentColorIndex", diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFMetadata.java b/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFMetadata.java index 42dfbd0bed9..8acdaa2db49 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFMetadata.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFMetadata.java @@ -158,13 +158,10 @@ abstract class GIFMetadata extends IIOMetadata { } } String value = attr.getNodeValue(); - // XXX Should be able to use equals() here instead of - // equalsIgnoreCase() but some boolean attributes are incorrectly - // set to "true" or "false" by the J2SE core metadata classes - // getAsTree() method (which are duplicated above). See bug 5082756. - if (value.equalsIgnoreCase("TRUE")) { + // Allow lower case booleans for backward compatibility, #5082756 + if (value.equals("TRUE") || value.equals("true")) { return true; - } else if (value.equalsIgnoreCase("FALSE")) { + } else if (value.equals("FALSE") || value.equals("false")) { return false; } else { fatal(node, "Attribute " + name + " must be 'TRUE' or 'FALSE'!"); diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadata.java b/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadata.java index 0979bf3d849..bc0a784b272 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadata.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadata.java @@ -202,7 +202,7 @@ public class GIFStreamMetadata extends GIFMetadata { compression_node.appendChild(node); node = new IIOMetadataNode("Lossless"); - node.setAttribute("value", "true"); + node.setAttribute("value", "TRUE"); compression_node.appendChild(node); // NumProgressiveScans not in stream diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java index 7f753341c93..c84003c9f22 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java @@ -955,7 +955,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { // Lossless - false IIOMetadataNode lossless = new IIOMetadataNode("Lossless"); - lossless.setAttribute("value", "false"); + lossless.setAttribute("value", "FALSE"); compression.appendChild(lossless); // NumProgressiveScans - count sos segments diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java b/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java index 23281fe5330..1ad78ad165f 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java @@ -600,7 +600,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { IIOMetadataNode iTXt_node = new IIOMetadataNode("iTXtEntry"); iTXt_node.setAttribute("keyword", iTXt_keyword.get(i)); iTXt_node.setAttribute("compressionFlag", - iTXt_compressionFlag.get(i) ? "1" : "0"); + iTXt_compressionFlag.get(i) ? "TRUE" : "FALSE"); iTXt_node.setAttribute("compressionMethod", iTXt_compressionMethod.get(i).toString()); iTXt_node.setAttribute("languageTag", @@ -832,7 +832,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { } node = new IIOMetadataNode("BlackIsZero"); - node.setAttribute("value", "true"); + node.setAttribute("value", "TRUE"); chroma_node.appendChild(node); if (PLTE_present) { @@ -894,7 +894,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { compression_node.appendChild(node); node = new IIOMetadataNode("Lossless"); - node.setAttribute("value", "true"); + node.setAttribute("value", "TRUE"); compression_node.appendChild(node); node = new IIOMetadataNode("NumProgressiveScans"); @@ -1162,12 +1162,13 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { } } String value = attr.getNodeValue(); - if (value.equals("true")) { + // Allow lower case booleans for backward compatibility, #5082756 + if (value.equals("TRUE") || value.equals("true")) { return true; - } else if (value.equals("false")) { + } else if (value.equals("FALSE") || value.equals("false")) { return false; } else { - fatal(node, "Attribute " + name + " must be 'true' or 'false'!"); + fatal(node, "Attribute " + name + " must be 'TRUE' or 'FALSE'!"); return false; } } diff --git a/jdk/src/share/classes/javax/imageio/metadata/IIOMetadataFormat.java b/jdk/src/share/classes/javax/imageio/metadata/IIOMetadataFormat.java index 88ea8e98756..cff46177d62 100644 --- a/jdk/src/share/classes/javax/imageio/metadata/IIOMetadataFormat.java +++ b/jdk/src/share/classes/javax/imageio/metadata/IIOMetadataFormat.java @@ -242,8 +242,12 @@ public interface IIOMetadataFormat { /** * A constant returned by getAttributeDataType - * indicating that the value of an attribute is one of 'true' or - * 'false'. + * indicating that the value of an attribute is one of the boolean + * values 'true' or 'false'. + * Attribute values of type DATATYPE_BOOLEAN should be marked as + * enumerations, and the permitted values should be the string + * literal values "TRUE" or "FALSE", although a plugin may also + * recognise lower or mixed case equivalents. */ int DATATYPE_BOOLEAN = 1; diff --git a/jdk/test/javax/imageio/metadata/BooleanAttributes.java b/jdk/test/javax/imageio/metadata/BooleanAttributes.java new file mode 100644 index 00000000000..104b12432c8 --- /dev/null +++ b/jdk/test/javax/imageio/metadata/BooleanAttributes.java @@ -0,0 +1,202 @@ +/* + * Copyright 2008 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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 5082756 + * @summary ensure that boolean attributes follow ( "TRUE" | "FALSE" ) + * including correct (i.e. upper) case + * + * @run main BooleanAttributes + */ + +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.StringReader; +import java.util.Arrays; +import java.util.List; +import javax.imageio.IIOImage; +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.ImageTypeSpecifier; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.stream.ImageInputStream; +import javax.imageio.stream.ImageOutputStream; +import javax.imageio.stream.MemoryCacheImageInputStream; +import javax.imageio.stream.MemoryCacheImageOutputStream; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.stream.StreamSource; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class BooleanAttributes { + + private static TransformerFactory transformerFactory = + TransformerFactory.newInstance(); + + private static XPath xpathEngine = XPathFactory.newInstance().newXPath(); + + public static void main(String[] args) throws Exception { + test("image/png", false, "", + "Chroma/BlackIsZero/@value", + "Compression/Lossless/@value"); + + test("image/png", false, + "" + + "" + + "", + "iTXt/iTXtEntry/@compressionFlag"); + + test("image/png", false, + "" + + "" + + "", + "iTXt/iTXtEntry/@compressionFlag"); + + test("image/gif", false, "", + "Chroma/BlackIsZero/@value", + "Compression/Lossless/@value"); + + test("image/gif", false, + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "", + "ImageDescriptor/@interlaceFlag", + "LocalColorTable/@sortFlag", + "GraphicControlExtension/@userInputFlag", + "GraphicControlExtension/@transparentColorFlag"); + + test("image/gif", true, + "" + + "" + + "" + + "" + + "" + + "", + "GlobalColorTable/@sortFlag"); + + test("image/jpeg", false, "", + "Compression/Lossless/@value"); + } + + private static void transform(Source src, Result dst) + throws Exception + { + transformerFactory.newTransformer().transform(src, dst); + } + + private static void verify(Node meta, String[] xpaths, boolean required) + throws Exception + { + for (String xpath: xpaths) { + NodeList list = (NodeList) + xpathEngine.evaluate(xpath, meta, XPathConstants.NODESET); + if (list.getLength() == 0 && required) + throw new AssertionError("Missing value: " + xpath); + for (int i = 0; i < list.getLength(); ++i) { + String value = list.item(i).getNodeValue(); + if (!(value.equals("TRUE") || value.equals("FALSE"))) + throw new AssertionError(xpath + " has value " + value); + } + } + } + + public static void test(String mimeType, boolean useStreamMeta, + String metaXml, String... boolXpaths) + throws Exception + { + BufferedImage img = + new BufferedImage(16, 16, BufferedImage.TYPE_INT_RGB); + ImageWriter iw = ImageIO.getImageWritersByMIMEType(mimeType).next(); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + ImageOutputStream ios = new MemoryCacheImageOutputStream(os); + iw.setOutput(ios); + ImageWriteParam param = null; + IIOMetadata streamMeta = iw.getDefaultStreamMetadata(param); + IIOMetadata imageMeta = + iw.getDefaultImageMetadata(new ImageTypeSpecifier(img), param); + IIOMetadata meta = useStreamMeta ? streamMeta : imageMeta; + Source src = new StreamSource(new StringReader(metaXml)); + DOMResult dst = new DOMResult(); + transform(src, dst); + Document doc = (Document)dst.getNode(); + Element node = doc.getDocumentElement(); + String metaFormat = node.getNodeName(); + + // Verify that the default metadata gets formatted correctly. + verify(meta.getAsTree(metaFormat), boolXpaths, false); + + meta.mergeTree(metaFormat, node); + + // Verify that the merged metadata gets formatte correctly. + verify(meta.getAsTree(metaFormat), boolXpaths, true); + + iw.write(streamMeta, new IIOImage(img, null, imageMeta), param); + iw.dispose(); + ios.close(); + ImageReader ir = ImageIO.getImageReader(iw); + byte[] bytes = os.toByteArray(); + if (bytes.length == 0) + throw new AssertionError("Zero length image file"); + ByteArrayInputStream is = new ByteArrayInputStream(bytes); + ImageInputStream iis = new MemoryCacheImageInputStream(is); + ir.setInput(iis); + if (useStreamMeta) meta = ir.getStreamMetadata(); + else meta = ir.getImageMetadata(0); + + // Verify again after writing and re-reading the image + verify(meta.getAsTree(metaFormat), boolXpaths, true); + } + + public static void xtest(Object... eatAnyArguments) { + System.err.println("Disabled test! Change xtest back into test!"); + } + +} diff --git a/jdk/test/javax/imageio/plugins/png/ITXtTest.java b/jdk/test/javax/imageio/plugins/png/ITXtTest.java index 9bace746227..ec81bd874ac 100644 --- a/jdk/test/javax/imageio/plugins/png/ITXtTest.java +++ b/jdk/test/javax/imageio/plugins/png/ITXtTest.java @@ -123,7 +123,7 @@ public class ITXtTest { } t.keyword = e.getAttribute("keyword"); t.isCompressed = - (Integer.valueOf(e.getAttribute("compressionFlag")).intValue() == 1); + Boolean.valueOf(e.getAttribute("compressionFlag")).booleanValue(); t.compression = Integer.valueOf(e.getAttribute("compressionMethod")).intValue(); t.language = e.getAttribute("languageTag"); From 57a1271b06b6a1cc4548fb353d8c0cf261eb0a38 Mon Sep 17 00:00:00 2001 From: Martin von Gagern Date: Tue, 13 Jan 2009 18:38:44 +0300 Subject: [PATCH 09/75] 6782079: PNG: reading metadata may cause OOM on truncated images Reviewed-by: igor, prr --- .../imageio/plugins/png/PNGImageReader.java | 45 ++-- .../imageio/plugins/png/PNGImageWriter.java | 9 +- .../sun/imageio/plugins/png/PNGMetadata.java | 43 ++-- .../imageio/plugins/png/ItxtUtf8Test.java | 241 ++++++++++++++++++ 4 files changed, 281 insertions(+), 57 deletions(-) create mode 100644 jdk/test/javax/imageio/plugins/png/ItxtUtf8Test.java diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java b/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java index 84a593264be..f35165420e9 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java @@ -37,6 +37,7 @@ import java.awt.image.WritableRaster; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.DataInputStream; +import java.io.EOFException; import java.io.InputStream; import java.io.IOException; import java.io.SequenceInputStream; @@ -59,7 +60,7 @@ import com.sun.imageio.plugins.common.SubImageInputStream; import java.io.ByteArrayOutputStream; import sun.awt.image.ByteInterleavedRaster; -class PNGImageDataEnumeration implements Enumeration { +class PNGImageDataEnumeration implements Enumeration { boolean firstTime = true; ImageInputStream stream; @@ -72,7 +73,7 @@ class PNGImageDataEnumeration implements Enumeration { int type = stream.readInt(); // skip chunk type } - public Object nextElement() { + public InputStream nextElement() { try { firstTime = false; ImageInputStream iis = new SubImageInputStream(stream, length); @@ -207,25 +208,17 @@ public class PNGImageReader extends ImageReader { resetStreamSettings(); } - private String readNullTerminatedString(String charset) throws IOException { + private String readNullTerminatedString(String charset, int maxLen) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); int b; - while ((b = stream.read()) != 0) { + int count = 0; + while ((maxLen > count++) && ((b = stream.read()) != 0)) { + if (b == -1) throw new EOFException(); baos.write(b); } return new String(baos.toByteArray(), charset); } - private String readNullTerminatedString() throws IOException { - StringBuilder b = new StringBuilder(); - int c; - - while ((c = stream.read()) != 0) { - b.append((char)c); - } - return b.toString(); - } - private void readHeader() throws IIOException { if (gotHeader) { return; @@ -434,7 +427,7 @@ public class PNGImageReader extends ImageReader { } private void parse_iCCP_chunk(int chunkLength) throws IOException { - String keyword = readNullTerminatedString(); + String keyword = readNullTerminatedString("ISO-8859-1", 80); metadata.iCCP_profileName = keyword; metadata.iCCP_compressionMethod = stream.readUnsignedByte(); @@ -450,7 +443,7 @@ public class PNGImageReader extends ImageReader { private void parse_iTXt_chunk(int chunkLength) throws IOException { long chunkStart = stream.getStreamPosition(); - String keyword = readNullTerminatedString(); + String keyword = readNullTerminatedString("ISO-8859-1", 80); metadata.iTXt_keyword.add(keyword); int compressionFlag = stream.readUnsignedByte(); @@ -459,15 +452,17 @@ public class PNGImageReader extends ImageReader { int compressionMethod = stream.readUnsignedByte(); metadata.iTXt_compressionMethod.add(Integer.valueOf(compressionMethod)); - String languageTag = readNullTerminatedString("UTF8"); + String languageTag = readNullTerminatedString("UTF8", 80); metadata.iTXt_languageTag.add(languageTag); + long pos = stream.getStreamPosition(); + int maxLen = (int)(chunkStart + chunkLength - pos); String translatedKeyword = - readNullTerminatedString("UTF8"); + readNullTerminatedString("UTF8", maxLen); metadata.iTXt_translatedKeyword.add(translatedKeyword); String text; - long pos = stream.getStreamPosition(); + pos = stream.getStreamPosition(); byte[] b = new byte[(int)(chunkStart + chunkLength - pos)]; stream.readFully(b); @@ -511,7 +506,7 @@ public class PNGImageReader extends ImageReader { private void parse_sPLT_chunk(int chunkLength) throws IOException, IIOException { - metadata.sPLT_paletteName = readNullTerminatedString(); + metadata.sPLT_paletteName = readNullTerminatedString("ISO-8859-1", 80); chunkLength -= metadata.sPLT_paletteName.length() + 1; int sampleDepth = stream.readUnsignedByte(); @@ -554,12 +549,12 @@ public class PNGImageReader extends ImageReader { } private void parse_tEXt_chunk(int chunkLength) throws IOException { - String keyword = readNullTerminatedString(); + String keyword = readNullTerminatedString("ISO-8859-1", 80); metadata.tEXt_keyword.add(keyword); byte[] b = new byte[chunkLength - keyword.length() - 1]; stream.readFully(b); - metadata.tEXt_text.add(new String(b)); + metadata.tEXt_text.add(new String(b, "ISO-8859-1")); } private void parse_tIME_chunk() throws IOException { @@ -640,7 +635,7 @@ public class PNGImageReader extends ImageReader { } private void parse_zTXt_chunk(int chunkLength) throws IOException { - String keyword = readNullTerminatedString(); + String keyword = readNullTerminatedString("ISO-8859-1", 80); metadata.zTXt_keyword.add(keyword); int method = stream.readUnsignedByte(); @@ -648,7 +643,7 @@ public class PNGImageReader extends ImageReader { byte[] b = new byte[chunkLength - keyword.length() - 2]; stream.readFully(b); - metadata.zTXt_text.add(new String(inflate(b))); + metadata.zTXt_text.add(new String(inflate(b), "ISO-8859-1")); } private void readMetadata() throws IIOException { @@ -1263,7 +1258,7 @@ public class PNGImageReader extends ImageReader { try { stream.seek(imageStartPosition); - Enumeration e = new PNGImageDataEnumeration(stream); + Enumeration e = new PNGImageDataEnumeration(stream); InputStream is = new SequenceInputStream(e); /* InflaterInputStream uses an Inflater instance which consumes diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java b/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java index ea4233a68ea..0f9cc785f92 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java @@ -674,13 +674,8 @@ public class PNGImageWriter extends ImageWriter { private byte[] deflate(byte[] b) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); DeflaterOutputStream dos = new DeflaterOutputStream(baos); - - int len = b.length; - for (int i = 0; i < len; i++) { - dos.write((int)(0xff & b[i])); - } + dos.write(b); dos.close(); - return baos.toByteArray(); } @@ -736,7 +731,7 @@ public class PNGImageWriter extends ImageWriter { cs.writeByte(compressionMethod); String text = (String)textIter.next(); - cs.write(deflate(text.getBytes())); + cs.write(deflate(text.getBytes("ISO-8859-1"))); cs.finish(); } } diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java b/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java index 1ad78ad165f..9da72298884 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java @@ -211,8 +211,8 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { public int sRGB_renderingIntent; // tEXt chunk - public ArrayList tEXt_keyword = new ArrayList(); // 1-79 char Strings - public ArrayList tEXt_text = new ArrayList(); // Strings + public ArrayList tEXt_keyword = new ArrayList(); // 1-79 characters + public ArrayList tEXt_text = new ArrayList(); // tIME chunk public boolean tIME_present; @@ -235,13 +235,13 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { public int tRNS_blue; // zTXt chunk - public ArrayList zTXt_keyword = new ArrayList(); // Strings - public ArrayList zTXt_compressionMethod = new ArrayList(); // Integers - public ArrayList zTXt_text = new ArrayList(); // Strings + public ArrayList zTXt_keyword = new ArrayList(); + public ArrayList zTXt_compressionMethod = new ArrayList(); + public ArrayList zTXt_text = new ArrayList(); // Unknown chunks - public ArrayList unknownChunkType = new ArrayList(); // Strings - public ArrayList unknownChunkData = new ArrayList(); // byte arrays + public ArrayList unknownChunkType = new ArrayList(); + public ArrayList unknownChunkData = new ArrayList(); public PNGMetadata() { super(true, @@ -426,21 +426,14 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return false; } - private ArrayList cloneBytesArrayList(ArrayList in) { + private ArrayList cloneBytesArrayList(ArrayList in) { if (in == null) { return null; } else { - ArrayList list = new ArrayList(in.size()); - Iterator iter = in.iterator(); - while (iter.hasNext()) { - Object o = iter.next(); - if (o == null) { - list.add(null); - } else { - list.add(((byte[])o).clone()); - } + ArrayList list = new ArrayList(in.size()); + for (byte[] b: in) { + list.add((b == null) ? null : (byte[])b.clone()); } - return list; } } @@ -2040,14 +2033,14 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { sBIT_present = false; sPLT_present = false; sRGB_present = false; - tEXt_keyword = new ArrayList(); - tEXt_text = new ArrayList(); + tEXt_keyword = new ArrayList(); + tEXt_text = new ArrayList(); tIME_present = false; tRNS_present = false; - zTXt_keyword = new ArrayList(); - zTXt_compressionMethod = new ArrayList(); - zTXt_text = new ArrayList(); - unknownChunkType = new ArrayList(); - unknownChunkData = new ArrayList(); + zTXt_keyword = new ArrayList(); + zTXt_compressionMethod = new ArrayList(); + zTXt_text = new ArrayList(); + unknownChunkType = new ArrayList(); + unknownChunkData = new ArrayList(); } } diff --git a/jdk/test/javax/imageio/plugins/png/ItxtUtf8Test.java b/jdk/test/javax/imageio/plugins/png/ItxtUtf8Test.java new file mode 100644 index 00000000000..e35495bdee1 --- /dev/null +++ b/jdk/test/javax/imageio/plugins/png/ItxtUtf8Test.java @@ -0,0 +1,241 @@ +/* + * Copyright 2008 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 6541476 6782079 + * @summary Write and read a PNG file including an non-latin1 iTXt chunk + * Test also verifies that trunkated png images does not cause + * an OoutOfMemory error. + * + * @run main ItxtUtf8Test + * + * @run main/othervm/timeout=10 -Xmx2m ItxtUtf8Test truncate + */ + +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.util.Arrays; +import java.util.List; +import javax.imageio.IIOException; +import javax.imageio.IIOImage; +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.ImageTypeSpecifier; +import javax.imageio.ImageWriter; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.stream.ImageInputStream; +import javax.imageio.stream.ImageOutputStream; +import javax.imageio.stream.MemoryCacheImageInputStream; +import javax.imageio.stream.MemoryCacheImageOutputStream; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.bootstrap.DOMImplementationRegistry; + +public class ItxtUtf8Test { + + public static final String + TEXT = "\u24c9\u24d4\u24e7\u24e3" + + "\ud835\udc13\ud835\udc1e\ud835\udc31\ud835\udc2d" + + "\u24c9\u24d4\u24e7\u24e3", // a repetition for compression + VERBATIM = "\u24e5\u24d4\u24e1\u24d1\u24d0\u24e3\u24d8\u24dc", + COMPRESSED = "\u24d2\u24de\u24dc\u24df\u24e1\u24d4\u24e2\u24e2\u24d4\u24d3"; + + public static final byte[] + VBYTES = { + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x56, // chunk length + (byte)0x69, (byte)0x54, (byte)0x58, (byte)0x74, // chunk type "iTXt" + (byte)0x76, (byte)0x65, (byte)0x72, (byte)0x62, + (byte)0x61, (byte)0x74, (byte)0x69, (byte)0x6d, // keyword "verbatim" + (byte)0x00, // separator terminating keyword + (byte)0x00, // compression flag + (byte)0x00, // compression method, must be zero + (byte)0x78, (byte)0x2d, (byte)0x63, (byte)0x69, + (byte)0x72, (byte)0x63, (byte)0x6c, (byte)0x65, + (byte)0x64, // language tag "x-circled" + (byte)0x00, // separator terminating language tag + (byte)0xe2, (byte)0x93, (byte)0xa5, // '\u24e5' + (byte)0xe2, (byte)0x93, (byte)0x94, // '\u24d4' + (byte)0xe2, (byte)0x93, (byte)0xa1, // '\u24e1' + (byte)0xe2, (byte)0x93, (byte)0x91, // '\u24d1' + (byte)0xe2, (byte)0x93, (byte)0x90, // '\u24d0' + (byte)0xe2, (byte)0x93, (byte)0xa3, // '\u24e3' + (byte)0xe2, (byte)0x93, (byte)0x98, // '\u24d8' + (byte)0xe2, (byte)0x93, (byte)0x9c, // '\u24dc' + (byte)0x00, // separator terminating the translated keyword + (byte)0xe2, (byte)0x93, (byte)0x89, // '\u24c9' + (byte)0xe2, (byte)0x93, (byte)0x94, // '\u24d4' + (byte)0xe2, (byte)0x93, (byte)0xa7, // '\u24e7' + (byte)0xe2, (byte)0x93, (byte)0xa3, // '\u24e3' + (byte)0xf0, (byte)0x9d, (byte)0x90, (byte)0x93, // '\ud835\udc13' + (byte)0xf0, (byte)0x9d, (byte)0x90, (byte)0x9e, // '\ud835\udc1e' + (byte)0xf0, (byte)0x9d, (byte)0x90, (byte)0xb1, // '\ud835\udc31' + (byte)0xf0, (byte)0x9d, (byte)0x90, (byte)0xad, // '\ud835\udc2d' + (byte)0xe2, (byte)0x93, (byte)0x89, // '\u24c9' + (byte)0xe2, (byte)0x93, (byte)0x94, // '\u24d4' + (byte)0xe2, (byte)0x93, (byte)0xa7, // '\u24e7' + (byte)0xe2, (byte)0x93, (byte)0xa3, // '\u24e3' + (byte)0xb5, (byte)0xcc, (byte)0x97, (byte)0x56 // CRC + }, + CBYTES = { + // we don't want to check the chunk length, + // as this might depend on implementation. + (byte)0x69, (byte)0x54, (byte)0x58, (byte)0x74, // chunk type "iTXt" + (byte)0x63, (byte)0x6f, (byte)0x6d, (byte)0x70, + (byte)0x72, (byte)0x65, (byte)0x73, (byte)0x73, + (byte)0x65, (byte)0x64, // keyword "compressed" + (byte)0x00, // separator terminating keyword + (byte)0x01, // compression flag + (byte)0x00, // compression method, 0=deflate + (byte)0x78, (byte)0x2d, (byte)0x63, (byte)0x69, + (byte)0x72, (byte)0x63, (byte)0x6c, (byte)0x65, + (byte)0x64, // language tag "x-circled" + (byte)0x00, // separator terminating language tag + // we don't want to check the actual compressed data, + // as this might depend on implementation. + }; +/* +*/ + + public static void main(String[] args) throws Exception { + List argList = Arrays.asList(args); + if (argList.contains("truncate")) { + try { + runTest(false, true); + throw new AssertionError("Expect an error for truncated file"); + } + catch (IIOException e) { + // expected an error for a truncated image file. + } + } + else { + runTest(argList.contains("dump"), false); + } + } + + public static void runTest(boolean dump, boolean truncate) + throws Exception + { + String format = "javax_imageio_png_1.0"; + BufferedImage img = + new BufferedImage(16, 16, BufferedImage.TYPE_INT_RGB); + ImageWriter iw = ImageIO.getImageWritersByMIMEType("image/png").next(); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + ImageOutputStream ios = new MemoryCacheImageOutputStream(os); + iw.setOutput(ios); + IIOMetadata meta = + iw.getDefaultImageMetadata(new ImageTypeSpecifier(img), null); + DOMImplementationRegistry registry; + registry = DOMImplementationRegistry.newInstance(); + DOMImplementation impl = registry.getDOMImplementation("XML 3.0"); + Document doc = impl.createDocument(null, format, null); + Element root, itxt, entry; + root = doc.getDocumentElement(); + root.appendChild(itxt = doc.createElement("iTXt")); + itxt.appendChild(entry = doc.createElement("iTXtEntry")); + entry.setAttribute("keyword", "verbatim"); + entry.setAttribute("compressionFlag", "false"); + entry.setAttribute("compressionMethod", "0"); + entry.setAttribute("languageTag", "x-circled"); + entry.setAttribute("translatedKeyword", VERBATIM); + entry.setAttribute("text", TEXT); + itxt.appendChild(entry = doc.createElement("iTXtEntry")); + entry.setAttribute("keyword", "compressed"); + entry.setAttribute("compressionFlag", "true"); + entry.setAttribute("compressionMethod", "0"); + entry.setAttribute("languageTag", "x-circled"); + entry.setAttribute("translatedKeyword", COMPRESSED); + entry.setAttribute("text", TEXT); + meta.mergeTree(format, root); + iw.write(new IIOImage(img, null, meta)); + iw.dispose(); + + byte[] bytes = os.toByteArray(); + if (dump) + System.out.write(bytes); + if (findBytes(VBYTES, bytes) < 0) + throw new AssertionError("verbatim block not found"); + if (findBytes(CBYTES, bytes) < 0) + throw new AssertionError("compressed block not found"); + int length = bytes.length; + if (truncate) + length = findBytes(VBYTES, bytes) + 32; + + ImageReader ir = ImageIO.getImageReader(iw); + ByteArrayInputStream is = new ByteArrayInputStream(bytes, 0, length); + ImageInputStream iis = new MemoryCacheImageInputStream(is); + ir.setInput(iis); + meta = ir.getImageMetadata(0); + Node node = meta.getAsTree(format); + for (node = node.getFirstChild(); + !"iTXt".equals(node.getNodeName()); + node = node.getNextSibling()); + boolean verbatimSeen = false, compressedSeen = false; + for (node = node.getFirstChild(); + node != null; + node = node.getNextSibling()) { + entry = (Element)node; + String keyword = entry.getAttribute("keyword"); + String translatedKeyword = entry.getAttribute("translatedKeyword"); + String text = entry.getAttribute("text"); + if ("verbatim".equals(keyword)) { + if (verbatimSeen) throw new AssertionError("Duplicate"); + verbatimSeen = true; + if (!VERBATIM.equals(translatedKeyword)) + throw new AssertionError("Wrong translated keyword"); + if (!TEXT.equals(text)) + throw new AssertionError("Wrong text"); + } + else if ("compressed".equals(keyword)) { + if (compressedSeen) throw new AssertionError("Duplicate"); + compressedSeen = true; + if (!COMPRESSED.equals(translatedKeyword)) + throw new AssertionError("Wrong translated keyword"); + if (!TEXT.equals(text)) + throw new AssertionError("Wrong text"); + } + else { + throw new AssertionError("Unexpected keyword"); + } + } + if (!(verbatimSeen && compressedSeen)) + throw new AssertionError("Missing chunk"); + } + + private static final int findBytes(byte[] needle, byte[] haystack) { + HAYSTACK: for (int h = 0; h <= haystack.length - needle.length; ++h) { + for (int n = 0; n < needle.length; ++n) { + if (needle[n] != haystack[h + n]) { + continue HAYSTACK; + } + } + return h; + } + return -1; + } + +} From 47a5b98c7f6ad40e66f40caa5d3017a5579870c7 Mon Sep 17 00:00:00 2001 From: Andrew Brygin Date: Thu, 15 Jan 2009 13:55:30 +0300 Subject: [PATCH 10/75] 6788096: ImageIO SreamCloser causes memory leak in FX applets Reviewed-by: igor, prr --- .../com/sun/imageio/stream/StreamCloser.java | 4 + .../stream/StreamCloserLeak/run_test.sh | 205 +++++++++++++ .../stream/StreamCloserLeak/test/Main.java | 284 ++++++++++++++++++ .../stream/StreamCloserLeak/testapp/Main.java | 109 +++++++ 4 files changed, 602 insertions(+) create mode 100644 jdk/test/javax/imageio/stream/StreamCloserLeak/run_test.sh create mode 100644 jdk/test/javax/imageio/stream/StreamCloserLeak/test/Main.java create mode 100644 jdk/test/javax/imageio/stream/StreamCloserLeak/testapp/Main.java diff --git a/jdk/src/share/classes/com/sun/imageio/stream/StreamCloser.java b/jdk/src/share/classes/com/sun/imageio/stream/StreamCloser.java index f39b98eb05d..03c6ce32364 100644 --- a/jdk/src/share/classes/com/sun/imageio/stream/StreamCloser.java +++ b/jdk/src/share/classes/com/sun/imageio/stream/StreamCloser.java @@ -94,6 +94,10 @@ public class StreamCloser { tgn != null; tg = tgn, tgn = tg.getParent()); streamCloser = new Thread(tg, streamCloserRunnable); + /* Set context class loader to null in order to avoid + * keeping a strong reference to an application classloader. + */ + streamCloser.setContextClassLoader(null); Runtime.getRuntime().addShutdownHook(streamCloser); return null; } diff --git a/jdk/test/javax/imageio/stream/StreamCloserLeak/run_test.sh b/jdk/test/javax/imageio/stream/StreamCloserLeak/run_test.sh new file mode 100644 index 00000000000..af3e428cb30 --- /dev/null +++ b/jdk/test/javax/imageio/stream/StreamCloserLeak/run_test.sh @@ -0,0 +1,205 @@ +#!/bin/ksh -p +# +# 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 6788096 +# @summary Test simulates the case of multiple applets executed in +# the same VM and verifies that ImageIO shutdown hook +# StreamCloser does not cause a leak of classloaders. +# +# @build test.Main +# @build testapp.Main +# @run shell run_test.sh + +# There are several resources which need to be present before many +# shell scripts can run. Following are examples of how to check for +# many common ones. +# +# Note that the shell used is the Korn Shell, KSH +# +# Also note, it is recommended that make files NOT be used. Rather, +# put the individual commands directly into this file. That way, +# it is possible to use command line arguments and other shell tech- +# niques to find the compiler, etc on different systems. For example, +# a different path could be used depending on whether this were a +# Solaris or Win32 machine, which is more difficult (if even possible) +# in a make file. + + +# Beginning of subroutines: +status=1 + +#Call this from anywhere to fail the test with an error message +# usage: fail "reason why the test failed" +fail() + { echo "The test failed :-(" + echo "$*" 1>&2 + echo "exit status was $status" + exit $status + } #end of fail() + +#Call this from anywhere to pass the test with a message +# usage: pass "reason why the test passed if applicable" +pass() + { echo "The test passed!!!" + echo "$*" 1>&2 + exit 0 + } #end of pass() + +# end of subroutines + + +# The beginning of the script proper + +# Checking for proper OS +OS=`uname -s` +case "$OS" in + SunOS ) + VAR="One value for Sun" + DEFAULT_JDK=/usr/local/java/jdk1.2/solaris + FILESEP="/" + PATHSEP=":" + TMP="/tmp" + ;; + + Linux ) + VAR="A different value for Linux" + DEFAULT_JDK=/usr/local/java/jdk1.4/linux-i386 + FILESEP="/" + PATHSEP=":" + TMP="/tmp" + ;; + + Windows_95 | Windows_98 | Windows_NT | Windows_ME ) + VAR="A different value for Win32" + DEFAULT_JDK=/usr/local/java/jdk1.2/win32 + FILESEP="\\" + PATHSEP=";" + TMP=`cd "${SystemRoot}/Temp"; echo ${PWD}` + ;; + + # catch all other OSs + * ) + echo "Unrecognized system! $OS" + fail "Unrecognized system! $OS" + ;; +esac + +# Want this test to run standalone as well as in the harness, so do the +# following to copy the test's directory into the harness's scratch directory +# and set all appropriate variables: + +if [ -z "${TESTJAVA}" ] ; then + # TESTJAVA is not set, so the test is running stand-alone. + # TESTJAVA holds the path to the root directory of the build of the JDK + # to be tested. That is, any java files run explicitly in this shell + # should use TESTJAVA in the path to the java interpreter. + # So, we'll set this to the JDK spec'd on the command line. If none + # is given on the command line, tell the user that and use a cheesy + # default. + # THIS IS THE JDK BEING TESTED. + if [ -n "$1" ] ; + then TESTJAVA=$1 + else echo "no JDK specified on command line so using default!" + TESTJAVA=$DEFAULT_JDK + fi + TESTSRC=. + TESTCLASSES=. + STANDALONE=1; +fi +echo "JDK under test is: $TESTJAVA" + + +############### YOUR TEST CODE HERE!!!!!!! ############# + +#All files required for the test should be in the same directory with +# this file. If converting a standalone test to run with the harness, +# as long as all files are in the same directory and it returns 0 for +# pass, you should be able to cut and paste it into here and it will +# run with the test harness. + +# This is an example of running something -- test +# The stuff below catches the exit status of test then passes or fails +# this shell test as appropriate ( 0 status is considered a pass here ) + +echo "Create TestApp.jar..." + +if [ -f TestApp.jar ] ; then + rm -f TestApp.jar +fi + +${TESTJAVA}/bin/jar -cvf TestApp.jar -C ${TESTCLASSES} testapp + +if [ $? -ne "0" ] ; then + fail "Failed to create TestApp.jar" +fi + +echo "Create Test.jar..." +if [ -f Test.jar ] ; then + rm -f Test.jar +fi + +${TESTJAVA}/bin/jar -cvf Test.jar -C ${TESTCLASSES} test + +if [ $? -ne 0 ] ; then + fail "Failed to create Test.jar" +fi + +# Prepare temp dir for cahce files +mkdir ./tmp +if [ $? -ne 0 ] ; then + fail "Unable to create temp directory." +fi + +# Verify that all classoladers are destroyed +${TESTJAVA}/bin/java -cp Test.jar test.Main +if [ $? -ne 0 ] ; then + fail "Test FAILED: some classloaders weren't destroyed." +fi + + +# Verify that ImageIO shutdown hook works correcly +${TESTJAVA}/bin/java -cp Test.jar -DforgetSomeStreams=true test.Main +if [ $? -ne 0 ] ; then + fail "Test FAILED: some classloaders weren't destroyed of shutdown hook failed." +fi + +# sanity check: verify that all cache files were deleted +cache_files=`ls tmp` + +if [ "x${cache_files}" != "x" ] ; then + echo "WARNING: some cache files was not deleted: ${cache_files}" +fi + +echo "Test done." + +status=$? + +if [ $status -eq "0" ] ; then + pass "" +else + fail "Test failed due to test plugin was not found." +fi + diff --git a/jdk/test/javax/imageio/stream/StreamCloserLeak/test/Main.java b/jdk/test/javax/imageio/stream/StreamCloserLeak/test/Main.java new file mode 100644 index 00000000000..b87299967c6 --- /dev/null +++ b/jdk/test/javax/imageio/stream/StreamCloserLeak/test/Main.java @@ -0,0 +1,284 @@ +/* + * 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. + */ + +package test; + +import java.io.File; +import java.io.IOException; +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.HashMap; +import java.util.Map.Entry; +import java.util.Set; +import java.util.WeakHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CountDownLatch; +import javax.imageio.stream.ImageInputStream; +import sun.awt.AppContext; +import sun.awt.SunToolkit; + +public class Main { + + private static ThreadGroup appsThreadGroup; + + private static WeakHashMap refs = + new WeakHashMap(); + + /** Collection to simulate forgrotten streams **/ + private static HashMap strongRefs = + new HashMap(); + + private static ConcurrentLinkedQueue problems = + new ConcurrentLinkedQueue(); + + private static AppContext mainAppContext = null; + + private static CountDownLatch doneSignal; + + private static final int gcTimeout = + Integer.getInteger("gcTimeout", 10).intValue(); + + private static boolean forgetSomeStreams = + Boolean.getBoolean("forgetSomeStreams"); + + public static void main(String[] args) throws IOException { + mainAppContext = SunToolkit.createNewAppContext(); + System.out.println("Current context class loader: " + + Thread.currentThread().getContextClassLoader()); + + appsThreadGroup = new ThreadGroup("MyAppsThreadGroup"); + + File jar = new File("TestApp.jar"); + if (!jar.exists()) { + System.out.println(jar.getAbsolutePath() + " was not found!\n" + + "Please install the jar with test application correctly!"); + throw new RuntimeException("Test failed: no TestApp.jar"); + } + + URL[] urls = new URL[]{jar.toURL()}; + + int numApps = Integer.getInteger("numApps", 20).intValue(); + + doneSignal = new CountDownLatch(numApps); + int cnt = 0; + while (cnt++ < numApps) { + launch(urls, "testapp.Main", "launch"); + + checkErrors(); + } + + System.out.println("Wait for apps completion...."); + + try { + doneSignal.await(); + } catch (InterruptedException e) { + } + + System.out.println("All apps finished."); + + System.gc(); + + System.out.flush(); + + System.out.println("Enumerate strong refs:"); + for (String is : strongRefs.keySet()) { + System.out.println("-> " + is); + } + + System.out.println("======================="); + + // wait few seconds + waitAndGC(gcTimeout); + + doneSignal = new CountDownLatch(1); + + Runnable workaround = new Runnable() { + + public void run() { + AppContext ctx = null; + try { + ctx = SunToolkit.createNewAppContext(); + } catch (Throwable e) { + // ignore... + } finally { + doneSignal.countDown(); + } + } + }; + + Thread wt = new Thread(appsThreadGroup, workaround, "Workaround"); + wt.setContextClassLoader(new MyClassLoader(urls, "workaround")); + wt.start(); + wt = null; + workaround = null; + + System.out.println("Wait for workaround completion..."); + + try { + doneSignal.await(); + } catch (InterruptedException e) { + } + + // give a chance to GC + waitAndGC(gcTimeout); + + if (!refs.isEmpty()) { + System.out.println("Classloaders still alive:"); + + for (MyClassLoader l : refs.keySet()) { + String val = refs.get(l); + + if (val == null) { + throw new RuntimeException("Test FAILED: Invalid classloader name"); + } + System.out.println("->" + val + (strongRefs.get(val) != null ? + " (has strong ref)" : "")); + if (strongRefs.get(val) == null) { + throw new RuntimeException("Test FAILED: exta class loader is detected! "); + } + } + } else { + System.out.println("No alive class loaders!!"); + } + System.out.println("Test PASSED."); + } + + private static void waitAndGC(int sec) { + int cnt = sec; + System.out.print("Wait "); + while (cnt-- > 0) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + // do GC every 3 seconds + if (cnt % 3 == 2) { + System.gc(); + System.out.print("+"); + } else { + System.out.print("."); + } + checkErrors(); + } + System.out.println(""); + } + + private static void checkErrors() { + while (!problems.isEmpty()) { + Throwable theProblem = problems.poll(); + System.out.println("Test FAILED!"); + do { + theProblem.printStackTrace(System.out); + theProblem = theProblem.getCause(); + } while (theProblem != null); + throw new RuntimeException("Test FAILED"); + } + } + static int counter = 0; + + private static void launch(URL[] urls, final String className, + final String methodName) + { + final String uniqClassName = "testapp/Uniq" + counter; + final boolean saveStrongRef = forgetSomeStreams ? (counter % 5 == 4) : false; + + System.out.printf("%s: launch the app\n", uniqClassName); + Runnable launchIt = new Runnable() { + public void run() { + AppContext ctx = SunToolkit.createNewAppContext(); + + try { + Class appMain = + ctx.getContextClassLoader().loadClass(className); + Method launch = appMain.getDeclaredMethod(methodName, + strongRefs.getClass()); + + Constructor c = appMain.getConstructor(String.class, + problems.getClass()); + + Object o = c.newInstance(uniqClassName, problems); + + if (saveStrongRef) { + System.out.printf("%s: force strong ref\n", + uniqClassName); + launch.invoke(o, strongRefs); + } else { + HashMap empty = null; + launch.invoke(o, empty); + } + + ctx = null; + } catch (Throwable e) { + problems.add(e); + } finally { + doneSignal.countDown(); + } + } + }; + + MyClassLoader appClassLoader = new MyClassLoader(urls, uniqClassName); + + refs.put(appClassLoader, uniqClassName); + + Thread appThread = new Thread(appsThreadGroup, launchIt, + "AppThread" + counter++); + appThread.setContextClassLoader(appClassLoader); + + appThread.start(); + launchIt = null; + appThread = null; + appClassLoader = null; + } + + private static class MyClassLoader extends URLClassLoader { + + private static boolean verbose = + Boolean.getBoolean("verboseClassLoading"); + private String uniqClassName; + + public MyClassLoader(URL[] urls, String uniq) { + super(urls); + + uniqClassName = uniq; + } + + public Class loadClass(String name) throws ClassNotFoundException { + if (verbose) { + System.out.printf("%s: load class %s\n", uniqClassName, name); + } + if (uniqClassName.equals(name)) { + return Object.class; + } + return super.loadClass(name); + } + + public String toString() { + return "MyClassLoader(" + uniqClassName + ")"; + } + } +} diff --git a/jdk/test/javax/imageio/stream/StreamCloserLeak/testapp/Main.java b/jdk/test/javax/imageio/stream/StreamCloserLeak/testapp/Main.java new file mode 100644 index 00000000000..3c4bb5ec3ff --- /dev/null +++ b/jdk/test/javax/imageio/stream/StreamCloserLeak/testapp/Main.java @@ -0,0 +1,109 @@ +/* + * 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. + */ + +package testapp; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import javax.imageio.stream.FileCacheImageInputStream; +import javax.imageio.stream.ImageInputStream; + +public class Main { + + public static void main(String[] args) { + Main o = new Main("testapp.some.class", null); + o.launch(null); + } + + private final String uniqClassName; + private final ConcurrentLinkedQueue problems; + + public Main(String uniq, ConcurrentLinkedQueue p) { + uniqClassName = uniq; + problems = p; + } + + public void launch(HashMap refs) { + System.out.printf("%s: current context class loader: %s\n", + uniqClassName, + Thread.currentThread().getContextClassLoader()); + try { + byte[] data = new byte[1024]; + ByteArrayInputStream bais = new ByteArrayInputStream(data); + MyImageInputStream iis = new MyImageInputStream(bais, + uniqClassName, + problems); + if (refs != null) { + System.out.printf("%s: added to strong store\n", + uniqClassName); + refs.put(uniqClassName, iis); + } + iis.read(); + //leave stream open : let's shutdown hook work! + } catch (IOException e) { + problems.add(e); + } + } + + private static class MyImageInputStream extends FileCacheImageInputStream { + private final String uniqClassName; + private ConcurrentLinkedQueue problems; + public MyImageInputStream(InputStream is, String uniq, + ConcurrentLinkedQueue p) throws IOException + { + super(is, new File("tmp")); + uniqClassName = uniq; + problems = p; + } + + @Override + public void close() throws IOException { + Test t = new Test(); + try { + t.doTest(uniqClassName); + } catch (Throwable e) { + problems.add(e); + } + + super.close(); + + problems = null; + } + } +} + +class Test { + public void doTest(String uniqClassName) throws ClassNotFoundException { + System.out.printf("%s: Current thread: %s\n", uniqClassName, + Thread.currentThread()); + + ClassLoader thisCL = this.getClass().getClassLoader(); + Class uniq = thisCL.loadClass(uniqClassName); + + System.out.printf("%s: test is done!\n",uniqClassName); + } +} From 8c2a336349c8ff82c6ab4484a68ca4b7dc4e11e1 Mon Sep 17 00:00:00 2001 From: Andrew Brygin Date: Fri, 23 Jan 2009 17:43:29 +0300 Subject: [PATCH 11/75] 6795544: GIFImageWriter does not write the subImage of BufferedImage to a file correctly Reviewed-by: igor, prr --- .../imageio/plugins/gif/GIFImageWriter.java | 16 +- .../plugins/gif/EncodeSubImageTest.java | 161 ++++++++++++++++++ 2 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 jdk/test/javax/imageio/plugins/gif/EncodeSubImageTest.java diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFImageWriter.java b/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFImageWriter.java index 4c7903bfe84..89f735d8793 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFImageWriter.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFImageWriter.java @@ -55,6 +55,7 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; import com.sun.imageio.plugins.common.LZWCompressor; import com.sun.imageio.plugins.common.PaletteBuilder; +import sun.awt.image.ByteComponentRaster; public class GIFImageWriter extends ImageWriter { private static final boolean DEBUG = false; // XXX false for release! @@ -905,10 +906,18 @@ public class GIFImageWriter extends ImageWriter { LZWCompressor compressor = new LZWCompressor(stream, initCodeSize, false); + /* At this moment we know that input image is indexed image. + * We can directly copy data iff: + * - no subsampling required (periodX = 1, periodY = 0) + * - we can access data directly (image is non-tiled, + * i.e. image data are in single block) + * - we can calculate offset in data buffer (next 3 lines) + */ boolean isOptimizedCase = periodX == 1 && periodY == 1 && - sampleModel instanceof ComponentSampleModel && image.getNumXTiles() == 1 && image.getNumYTiles() == 1 && + sampleModel instanceof ComponentSampleModel && + image.getTile(0, 0) instanceof ByteComponentRaster && image.getTile(0, 0).getDataBuffer() instanceof DataBufferByte; int numRowsWritten = 0; @@ -921,11 +930,14 @@ public class GIFImageWriter extends ImageWriter { if (DEBUG) System.out.println("Writing interlaced"); if (isOptimizedCase) { - Raster tile = image.getTile(0, 0); + ByteComponentRaster tile = + (ByteComponentRaster)image.getTile(0, 0); byte[] data = ((DataBufferByte)tile.getDataBuffer()).getData(); ComponentSampleModel csm = (ComponentSampleModel)tile.getSampleModel(); int offset = csm.getOffset(sourceXOffset, sourceYOffset, 0); + // take into account the raster data offset + offset += tile.getDataOffset(0); int lineStride = csm.getScanlineStride(); writeRowsOpt(data, offset, lineStride, compressor, diff --git a/jdk/test/javax/imageio/plugins/gif/EncodeSubImageTest.java b/jdk/test/javax/imageio/plugins/gif/EncodeSubImageTest.java new file mode 100644 index 00000000000..407242161c2 --- /dev/null +++ b/jdk/test/javax/imageio/plugins/gif/EncodeSubImageTest.java @@ -0,0 +1,161 @@ +/* + * 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 6795544 + * + * @summary Test verifes that Image I/O gif writer correctly handles + * buffered images based on translated reasters (typically + * produced by getSubImage() method). + * + * @run main EncodeSubImageTest gif + */ + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import java.awt.image.Raster; +import java.io.File; +import java.io.IOException; +import javax.imageio.IIOImage; +import javax.imageio.ImageIO; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.stream.ImageOutputStream; + +public class EncodeSubImageTest { + private static String format = "gif"; + private static ImageWriter writer; + private static String file_suffix; + private static final int subSampleX = 2; + private static final int subSampleY = 2; + + public static void main(String[] args) throws IOException { + if (args.length > 0) { + format = args[0]; + } + + writer = ImageIO.getImageWritersByFormatName(format).next(); + + file_suffix =writer.getOriginatingProvider().getFileSuffixes()[0]; + + BufferedImage src = createTestImage(); + EncodeSubImageTest m1 = new EncodeSubImageTest(src); + m1.doTest("test_src"); + + BufferedImage sub = src.getSubimage(subImageOffset, subImageOffset, + src.getWidth() - 2 * subImageOffset, + src.getHeight() - 2 * subImageOffset); + EncodeSubImageTest m2 = new EncodeSubImageTest(sub); + m2.doTest("test_sub"); + } + + BufferedImage img; + + public EncodeSubImageTest(BufferedImage img) { + this.img = img; + } + + public void doTest(String prefix) throws IOException { + System.out.println(prefix); + File f = new File(prefix + file_suffix); + write(f, false); + verify(f, false); + + System.out.println(prefix + "_subsampled"); + f = new File(prefix + "_subsampled"); + write(f, true); + verify(f, true); + + System.out.println(prefix + ": Test PASSED."); + } + + private static final int subImageOffset = 10; + + private void verify(File f, boolean isSubsampled) { + BufferedImage dst = null; + try { + dst = ImageIO.read(f); + } catch (IOException e) { + throw new RuntimeException("Test FAILED: can't readin test image " + + f.getAbsolutePath(), e); + } + if (dst == null) { + throw new RuntimeException("Test FAILED: no dst image available."); + } + + checkPixel(dst, 0, 0, isSubsampled); + + checkPixel(dst, img.getWidth() / 2, img.getHeight() / 2, isSubsampled); + } + + private void checkPixel(BufferedImage dst, int x, int y, + boolean isSubsampled) + { + int dx = isSubsampled ? x / subSampleX : x; + int dy = isSubsampled ? y / subSampleY : y; + int src_rgb = img.getRGB(x, y); + System.out.printf("src_rgb: %x\n", src_rgb); + + int dst_rgb = dst.getRGB(dx, dy); + System.out.printf("dst_rgb: %x\n", dst_rgb); + + if (src_rgb != dst_rgb) { + throw new RuntimeException("Test FAILED: invalid color in dst"); + } + } + + private static BufferedImage createTestImage() { + int w = 100; + int h = 100; + + BufferedImage src = new BufferedImage(w, h, + BufferedImage.TYPE_BYTE_INDEXED); + Graphics g = src.createGraphics(); + g.setColor(Color.red); + g.fillRect(0, 0, w, h); + g.setColor(Color.green); + g.fillRect(subImageOffset, subImageOffset, + w - 2 * subImageOffset, h - 2* subImageOffset); + g.setColor(Color.blue); + g.fillRect(2 * subImageOffset, 2 * subImageOffset, + w - 4 * subImageOffset, h - 4 * subImageOffset); + g.dispose(); + + return src; + } + + private void write(File f, boolean subsample) throws IOException { + ImageOutputStream ios = ImageIO.createImageOutputStream(f); + + writer.setOutput(ios); + ImageWriteParam p = writer.getDefaultWriteParam(); + if (subsample) { + p.setSourceSubsampling(subSampleX, subSampleY, 0, 0); + } + writer.write(null, new IIOImage(img, null, null), p); + ios.close(); + writer.reset(); + } +} From 2726f2a3621dd2562d4fb660b4c3d376c65027aa Mon Sep 17 00:00:00 2001 From: Andrew Brygin Date: Fri, 23 Jan 2009 21:14:31 +0300 Subject: [PATCH 12/75] 6793818: JpegImageReader is too greedy creating color profiles Reviewed-by: igor, prr --- .../classes/java/awt/color/ICC_Profile.java | 78 +++++++++++-------- .../sun/java2d/cmm/ProfileActivator.java | 3 +- .../sun/java2d/cmm/ProfileDeferralMgr.java | 27 ++++++- 3 files changed, 71 insertions(+), 37 deletions(-) diff --git a/jdk/src/share/classes/java/awt/color/ICC_Profile.java b/jdk/src/share/classes/java/awt/color/ICC_Profile.java index 3ef8d437bb4..705d2560e1f 100644 --- a/jdk/src/share/classes/java/awt/color/ICC_Profile.java +++ b/jdk/src/share/classes/java/awt/color/ICC_Profile.java @@ -737,7 +737,7 @@ public class ICC_Profile implements Serializable { ICC_Profile(ProfileDeferralInfo pdi) { this.deferralInfo = pdi; this.profileActivator = new ProfileActivator() { - public void activate() { + public void activate() throws ProfileDataException { activateDeferredProfile(); } }; @@ -830,20 +830,16 @@ public class ICC_Profile implements Serializable { case ColorSpace.CS_sRGB: synchronized(ICC_Profile.class) { if (sRGBprofile == null) { - try { - /* - * Deferral is only used for standard profiles. - * Enabling the appropriate access privileges is handled - * at a lower level. - */ - sRGBprofile = getDeferredInstance( - new ProfileDeferralInfo("sRGB.pf", - ColorSpace.TYPE_RGB, - 3, CLASS_DISPLAY)); - } catch (IOException e) { - throw new IllegalArgumentException( - "Can't load standard profile: sRGB.pf"); - } + /* + * Deferral is only used for standard profiles. + * Enabling the appropriate access privileges is handled + * at a lower level. + */ + ProfileDeferralInfo pInfo = + new ProfileDeferralInfo("sRGB.pf", + ColorSpace.TYPE_RGB, 3, + CLASS_DISPLAY); + sRGBprofile = getDeferredInstance(pInfo); } thisProfile = sRGBprofile; } @@ -853,7 +849,11 @@ public class ICC_Profile implements Serializable { case ColorSpace.CS_CIEXYZ: synchronized(ICC_Profile.class) { if (XYZprofile == null) { - XYZprofile = getStandardProfile("CIEXYZ.pf"); + ProfileDeferralInfo pInfo = + new ProfileDeferralInfo("CIEXYZ.pf", + ColorSpace.TYPE_XYZ, 3, + CLASS_DISPLAY); + XYZprofile = getDeferredInstance(pInfo); } thisProfile = XYZprofile; } @@ -863,7 +863,11 @@ public class ICC_Profile implements Serializable { case ColorSpace.CS_PYCC: synchronized(ICC_Profile.class) { if (PYCCprofile == null) { - PYCCprofile = getStandardProfile("PYCC.pf"); + ProfileDeferralInfo pInfo = + new ProfileDeferralInfo("PYCC.pf", + ColorSpace.TYPE_3CLR, 3, + CLASS_DISPLAY); + PYCCprofile = getDeferredInstance(pInfo); } thisProfile = PYCCprofile; } @@ -873,7 +877,11 @@ public class ICC_Profile implements Serializable { case ColorSpace.CS_GRAY: synchronized(ICC_Profile.class) { if (GRAYprofile == null) { - GRAYprofile = getStandardProfile("GRAY.pf"); + ProfileDeferralInfo pInfo = + new ProfileDeferralInfo("GRAY.pf", + ColorSpace.TYPE_GRAY, 1, + CLASS_DISPLAY); + GRAYprofile = getDeferredInstance(pInfo); } thisProfile = GRAYprofile; } @@ -883,7 +891,11 @@ public class ICC_Profile implements Serializable { case ColorSpace.CS_LINEAR_RGB: synchronized(ICC_Profile.class) { if (LINEAR_RGBprofile == null) { - LINEAR_RGBprofile = getStandardProfile("LINEAR_RGB.pf"); + ProfileDeferralInfo pInfo = + new ProfileDeferralInfo("LINEAR_RGB.pf", + ColorSpace.TYPE_RGB, 3, + CLASS_DISPLAY); + LINEAR_RGBprofile = getDeferredInstance(pInfo); } thisProfile = LINEAR_RGBprofile; } @@ -1047,9 +1059,7 @@ public class ICC_Profile implements Serializable { * code will take care of access privileges. * @see activateDeferredProfile() */ - static ICC_Profile getDeferredInstance(ProfileDeferralInfo pdi) - throws IOException { - + static ICC_Profile getDeferredInstance(ProfileDeferralInfo pdi) { if (!ProfileDeferralMgr.deferring) { return getStandardProfile(pdi.filename); } @@ -1063,33 +1073,37 @@ public class ICC_Profile implements Serializable { } - void activateDeferredProfile() { - byte profileData[]; - FileInputStream fis; - String fileName = deferralInfo.filename; + void activateDeferredProfile() throws ProfileDataException { + byte profileData[]; + FileInputStream fis; + String fileName = deferralInfo.filename; profileActivator = null; deferralInfo = null; if ((fis = openProfile(fileName)) == null) { - throw new IllegalArgumentException("Cannot open file " + fileName); + throw new ProfileDataException("Cannot open file " + fileName); } try { profileData = getProfileDataFromStream(fis); fis.close(); /* close the file */ } catch (IOException e) { - throw new IllegalArgumentException("Invalid ICC Profile Data" + - fileName); + ProfileDataException pde = new + ProfileDataException("Invalid ICC Profile Data" + fileName); + pde.initCause(e); + throw pde; } if (profileData == null) { - throw new IllegalArgumentException("Invalid ICC Profile Data" + + throw new ProfileDataException("Invalid ICC Profile Data" + fileName); } try { ID = CMSManager.getModule().loadProfile(profileData); } catch (CMMException c) { - throw new IllegalArgumentException("Invalid ICC Profile Data" + - fileName); + ProfileDataException pde = new + ProfileDataException("Invalid ICC Profile Data" + fileName); + pde.initCause(c); + throw pde; } } diff --git a/jdk/src/share/classes/sun/java2d/cmm/ProfileActivator.java b/jdk/src/share/classes/sun/java2d/cmm/ProfileActivator.java index 32c4e477fb9..f5a28f84232 100644 --- a/jdk/src/share/classes/sun/java2d/cmm/ProfileActivator.java +++ b/jdk/src/share/classes/sun/java2d/cmm/ProfileActivator.java @@ -25,6 +25,7 @@ package sun.java2d.cmm; +import java.awt.color.ProfileDataException; /** * An interface to allow the ProfileDeferralMgr to activate a @@ -35,6 +36,6 @@ public interface ProfileActivator { /** * Activate a previously deferred ICC_Profile object. */ - public void activate(); + public void activate() throws ProfileDataException; } diff --git a/jdk/src/share/classes/sun/java2d/cmm/ProfileDeferralMgr.java b/jdk/src/share/classes/sun/java2d/cmm/ProfileDeferralMgr.java index 41804c3fd9b..116f339da0a 100644 --- a/jdk/src/share/classes/sun/java2d/cmm/ProfileDeferralMgr.java +++ b/jdk/src/share/classes/sun/java2d/cmm/ProfileDeferralMgr.java @@ -25,6 +25,7 @@ package sun.java2d.cmm; +import java.awt.color.ProfileDataException; import java.util.Vector; @@ -39,7 +40,7 @@ import java.util.Vector; public class ProfileDeferralMgr { public static boolean deferring = true; - private static Vector aVector; + private static Vector aVector; /** * Records a ProfileActivator object whose activate method will @@ -51,7 +52,7 @@ public class ProfileDeferralMgr { return; } if (aVector == null) { - aVector = new Vector(3, 3); + aVector = new Vector(3, 3); } aVector.addElement(pa); return; @@ -89,8 +90,26 @@ public class ProfileDeferralMgr { return; } n = aVector.size(); - for (i = 0; i < n; i++) { - ((ProfileActivator) aVector.get(i)).activate(); + for (ProfileActivator pa : aVector) { + try { + pa.activate(); + } catch (ProfileDataException e) { + /* + * Ignore profile activation error for now: + * such exception is pssible due to absence + * or corruption of standard color profile. + * As for now we expect all profiles should + * be shiped with jre and presence of this + * exception is indication of some configuration + * problem in jre installation. + * + * NB: we still are greedy loading deferred profiles + * and load them all if any of them is needed. + * Therefore broken profile (if any) might be never used. + * If there will be attempt to use broken profile then + * it will result in CMMException. + */ + } } aVector.removeAllElements(); aVector = null; From 55076b2558a836ff91b27c6cee714f39cae75878 Mon Sep 17 00:00:00 2001 From: Red Hat Date: Wed, 28 Jan 2009 09:38:55 -0800 Subject: [PATCH 13/75] 6793344: BasicStroke's first element dash pattern is not a dash Reviewed-by: igor, flar --- .../classes/sun/java2d/pisces/Dasher.java | 2 +- jdk/test/sun/pisces/DashStrokeTest.java | 86 +++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 jdk/test/sun/pisces/DashStrokeTest.java diff --git a/jdk/src/share/classes/sun/java2d/pisces/Dasher.java b/jdk/src/share/classes/sun/java2d/pisces/Dasher.java index 81c92f44a60..99215e01b8e 100644 --- a/jdk/src/share/classes/sun/java2d/pisces/Dasher.java +++ b/jdk/src/share/classes/sun/java2d/pisces/Dasher.java @@ -120,7 +120,7 @@ public class Dasher extends LineSink { // Normalize so 0 <= phase < dash[0] int idx = 0; - dashOn = false; + dashOn = true; int d; while (phase >= (d = dash[idx])) { phase -= d; diff --git a/jdk/test/sun/pisces/DashStrokeTest.java b/jdk/test/sun/pisces/DashStrokeTest.java new file mode 100644 index 00000000000..f77acbeacfe --- /dev/null +++ b/jdk/test/sun/pisces/DashStrokeTest.java @@ -0,0 +1,86 @@ +/* + * 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 + * @summary verify that first element is a dash + * @bug 6793344 + */ + +import java.awt.*; +import java.awt.image.*; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; + +public class DashStrokeTest extends Component { + + static BufferedImage bi; + static boolean printed = false; + + public Dimension getPreferredSize() { + return new Dimension(200,200); + } + + public static void drawGui() { + bi = new BufferedImage(200, 20, BufferedImage.TYPE_INT_RGB); + Graphics2D g2d = bi.createGraphics(); + BasicStroke dashStroke = new BasicStroke(1.0f, BasicStroke.CAP_ROUND, + BasicStroke.JOIN_ROUND, 1.0f, new float[] { 0.0f, 200 }, + 1.0f); + + g2d.setStroke(dashStroke); + g2d.setColor(Color.RED); + g2d.drawLine(5,10, 100,10); + printed =true; + } + + public static void main(String[] args) { + try { + SwingUtilities.invokeAndWait(new Runnable() { + + @Override + public void run() { + drawGui(); + } + + }); + } catch (Exception e) { + } + + if (printed) { + checkBI(bi, Color.RED); + } + } + + static void checkBI(BufferedImage bi, Color badColor) { + int badrgb = badColor.getRGB(); + + int col = bi.getRGB(6, 9); + if (col == badrgb) { + throw new RuntimeException("A pixel was turned on. "); + } + } +} + From 2a2bbe287903c73e0de793d2f1c6a2bb88125151 Mon Sep 17 00:00:00 2001 From: Andrew Brygin Date: Thu, 29 Jan 2009 13:19:34 +0300 Subject: [PATCH 14/75] 6631559: Registration of ImageIO plugins should not cause loading of jpeg.dlli and cmm.dll Reviewed-by: igor, prr --- .../plugins/jpeg/JFIFMarkerSegment.java | 2 +- .../com/sun/imageio/plugins/jpeg/JPEG.java | 25 +- .../imageio/plugins/jpeg/JPEGImageReader.java | 26 +- .../plugins/jpeg/JPEGImageReaderSpi.java | 22 -- .../imageio/plugins/jpeg/JPEGImageWriter.java | 10 +- .../plugins/jpeg/JPEGImageWriterSpi.java | 19 -- .../imageio/plugins/jpeg/JPEGMetadata.java | 2 +- .../javax/imageio/ImageTypeSpecifier.java | 247 +++++++++--------- 8 files changed, 167 insertions(+), 186 deletions(-) diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JFIFMarkerSegment.java b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JFIFMarkerSegment.java index 883bd1a7447..d59a8885c9b 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JFIFMarkerSegment.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JFIFMarkerSegment.java @@ -1003,7 +1003,7 @@ class JFIFMarkerSegment extends MarkerSegment { 3, new int [] {0, 1, 2}, null); - ColorModel cm = new ComponentColorModel(JPEG.sRGB, + ColorModel cm = new ComponentColorModel(JPEG.JCS.sRGB, false, false, ColorModel.OPAQUE, diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEG.java b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEG.java index b16669bc089..3ed5c5083c3 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEG.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEG.java @@ -208,15 +208,24 @@ public class JPEG { public static final int [] bOffsRGB = { 2, 1, 0 }; - protected static final ColorSpace sRGB = - ColorSpace.getInstance(ColorSpace.CS_sRGB); - protected static ColorSpace YCC = null; // Can't be final + /* These are kept in the inner class to avoid static initialization + * of the CMM class until someone actually needs it. + * (e.g. do not init CMM on the request for jpeg mime types) + */ + public static class JCS { + public static final ColorSpace sRGB = + ColorSpace.getInstance(ColorSpace.CS_sRGB); + public static final ColorSpace YCC; - static { - try { - YCC = ColorSpace.getInstance(ColorSpace.CS_PYCC); - } catch (IllegalArgumentException e) { - // PYCC.pf may not always be installed + static { + ColorSpace cs = null; + try { + cs = ColorSpace.getInstance(ColorSpace.CS_PYCC); + } catch (IllegalArgumentException e) { + // PYCC.pf may not always be installed + } finally { + YCC = cs; + } } } diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java index 48afd2f354c..faf8261544c 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java @@ -228,31 +228,31 @@ public class JPEGImageReader extends ImageReader { (BufferedImage.TYPE_BYTE_GRAY); defaultTypes[JPEG.JCS_RGB] = ImageTypeSpecifier.createInterleaved - (JPEG.sRGB, + (JPEG.JCS.sRGB, JPEG.bOffsRGB, DataBuffer.TYPE_BYTE, false, false); defaultTypes[JPEG.JCS_RGBA] = ImageTypeSpecifier.createPacked - (JPEG.sRGB, + (JPEG.JCS.sRGB, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff, DataBuffer.TYPE_INT, false); - if (JPEG.YCC != null) { + if (JPEG.JCS.YCC != null) { defaultTypes[JPEG.JCS_YCC] = ImageTypeSpecifier.createInterleaved - (JPEG.YCC, + (JPEG.JCS.YCC, JPEG.bandOffsets[2], DataBuffer.TYPE_BYTE, false, false); defaultTypes[JPEG.JCS_YCCA] = ImageTypeSpecifier.createInterleaved - (JPEG.YCC, + (JPEG.JCS.YCC, JPEG.bandOffsets[3], DataBuffer.TYPE_BYTE, true, @@ -774,7 +774,7 @@ public class JPEGImageReader extends ImageReader { case JPEG.JCS_RGB: list.add(raw); list.add(getImageType(JPEG.JCS_GRAYSCALE)); - if (JPEG.YCC != null) { + if (JPEG.JCS.YCC != null) { list.add(getImageType(JPEG.JCS_YCC)); } break; @@ -811,7 +811,7 @@ public class JPEGImageReader extends ImageReader { } list.add(getImageType(JPEG.JCS_GRAYSCALE)); - if (JPEG.YCC != null) { // Might be null if PYCC.pf not installed + if (JPEG.JCS.YCC != null) { // Might be null if PYCC.pf not installed list.add(getImageType(JPEG.JCS_YCC)); } break; @@ -893,7 +893,7 @@ public class JPEGImageReader extends ImageReader { (!cs.isCS_sRGB()) && (cm.getNumComponents() == numComponents)) { // Target isn't sRGB, so convert from sRGB to the target - convert = new ColorConvertOp(JPEG.sRGB, cs, null); + convert = new ColorConvertOp(JPEG.JCS.sRGB, cs, null); } else if (csType != ColorSpace.TYPE_RGB) { throw new IIOException("Incompatible color conversion"); } @@ -906,18 +906,18 @@ public class JPEGImageReader extends ImageReader { } break; case JPEG.JCS_YCC: - if (JPEG.YCC == null) { // We can't do YCC at all + if (JPEG.JCS.YCC == null) { // We can't do YCC at all throw new IIOException("Incompatible color conversion"); } - if ((cs != JPEG.YCC) && + if ((cs != JPEG.JCS.YCC) && (cm.getNumComponents() == numComponents)) { - convert = new ColorConvertOp(JPEG.YCC, cs, null); + convert = new ColorConvertOp(JPEG.JCS.YCC, cs, null); } break; case JPEG.JCS_YCCA: // No conversions available; image must be YCCA - if ((JPEG.YCC == null) || // We can't do YCC at all - (cs != JPEG.YCC) || + if ((JPEG.JCS.YCC == null) || // We can't do YCC at all + (cs != JPEG.JCS.YCC) || (cm.getNumComponents() != numComponents)) { throw new IIOException("Incompatible color conversion"); } diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderSpi.java b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderSpi.java index 5bed06158af..13327e3ea9c 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderSpi.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderSpi.java @@ -39,8 +39,6 @@ public class JPEGImageReaderSpi extends ImageReaderSpi { private static String [] writerSpiNames = {"com.sun.imageio.plugins.jpeg.JPEGImageWriterSpi"}; - private boolean registered = false; - public JPEGImageReaderSpi() { super(JPEG.vendor, JPEG.version, @@ -61,26 +59,6 @@ public class JPEGImageReaderSpi extends ImageReaderSpi { ); } - public void onRegistration(ServiceRegistry registry, - Class category) { - if (registered) { - return; - } - try { - java.security.AccessController.doPrivileged( - new sun.security.action.LoadLibraryAction("jpeg")); - // Stuff it all into one lib for first pass - //java.security.AccessController.doPrivileged( - //new sun.security.action.LoadLibraryAction("imageioIJG")); - } catch (Throwable e) { // Fail on any Throwable - // if it can't be loaded, deregister and return - registry.deregisterServiceProvider(this); - return; - } - - registered = true; - } - public String getDescription(Locale locale) { return "Standard JPEG Image Reader"; } diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java index 0fbe8f33945..9c585047faa 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java @@ -812,13 +812,13 @@ public class JPEGImageWriter extends ImageWriter { } break; case ColorSpace.TYPE_3CLR: - if (cs == JPEG.YCC) { + if (cs == JPEG.JCS.YCC) { if (!alpha) { if (jfif != null) { convertTosRGB = true; convertOp = new ColorConvertOp(cs, - JPEG.sRGB, + JPEG.JCS.sRGB, null); outCsType = JPEG.JCS_YCbCr; } else if (adobe != null) { @@ -1494,7 +1494,7 @@ public class JPEGImageWriter extends ImageWriter { } break; case ColorSpace.TYPE_3CLR: - if (cs == JPEG.YCC) { + if (cs == JPEG.JCS.YCC) { if (alpha) { retval = JPEG.JCS_YCCA; } else { @@ -1533,7 +1533,7 @@ public class JPEGImageWriter extends ImageWriter { } break; case ColorSpace.TYPE_3CLR: - if (cs == JPEG.YCC) { + if (cs == JPEG.JCS.YCC) { if (alpha) { retval = JPEG.JCS_YCCA; } else { @@ -1579,7 +1579,7 @@ public class JPEGImageWriter extends ImageWriter { } break; case ColorSpace.TYPE_3CLR: - if (cs == JPEG.YCC) { + if (cs == JPEG.JCS.YCC) { if (alpha) { retval = JPEG.JCS_YCCA; } else { diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterSpi.java b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterSpi.java index 936c65c544f..717b4360794 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterSpi.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterSpi.java @@ -42,8 +42,6 @@ public class JPEGImageWriterSpi extends ImageWriterSpi { private static String [] readerSpiNames = {"com.sun.imageio.plugins.jpeg.JPEGImageReaderSpi"}; - private boolean registered = false; - public JPEGImageWriterSpi() { super(JPEG.vendor, JPEG.version, @@ -68,23 +66,6 @@ public class JPEGImageWriterSpi extends ImageWriterSpi { return "Standard JPEG Image Writer"; } - public void onRegistration(ServiceRegistry registry, - Class category) { - if (registered) { - return; - } - try { - java.security.AccessController.doPrivileged( - new sun.security.action.LoadLibraryAction("jpeg")); - } catch (Throwable e) { // Fail on any Throwable - // if it can't be loaded, deregister and return - registry.deregisterServiceProvider(this); - return; - } - - registered = true; - } - public boolean isFormatLossless() { return false; } diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java index c84003c9f22..044f7d632f6 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java @@ -490,7 +490,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { } break; case ColorSpace.TYPE_3CLR: - if (cs == JPEG.YCC) { + if (cs == JPEG.JCS.YCC) { wantJFIF = false; componentIDs[0] = (byte) 'Y'; componentIDs[1] = (byte) 'C'; diff --git a/jdk/src/share/classes/javax/imageio/ImageTypeSpecifier.java b/jdk/src/share/classes/javax/imageio/ImageTypeSpecifier.java index 4ba0c1062d4..184bf8870cc 100644 --- a/jdk/src/share/classes/javax/imageio/ImageTypeSpecifier.java +++ b/jdk/src/share/classes/javax/imageio/ImageTypeSpecifier.java @@ -67,126 +67,13 @@ public class ImageTypeSpecifier { * BufferedImage types. */ private static ImageTypeSpecifier[] BISpecifier; - + private static ColorSpace sRGB; // Initialize the standard specifiers static { - ColorSpace sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB); + sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB); BISpecifier = new ImageTypeSpecifier[BufferedImage.TYPE_BYTE_INDEXED + 1]; - - BISpecifier[BufferedImage.TYPE_CUSTOM] = null; - - BISpecifier[BufferedImage.TYPE_INT_RGB] = - createPacked(sRGB, - 0x00ff0000, - 0x0000ff00, - 0x000000ff, - 0x0, - DataBuffer.TYPE_INT, - false); - - BISpecifier[BufferedImage.TYPE_INT_ARGB] = - createPacked(sRGB, - 0x00ff0000, - 0x0000ff00, - 0x000000ff, - 0xff000000, - DataBuffer.TYPE_INT, - false); - - BISpecifier[BufferedImage.TYPE_INT_ARGB_PRE] = - createPacked(sRGB, - 0x00ff0000, - 0x0000ff00, - 0x000000ff, - 0xff000000, - DataBuffer.TYPE_INT, - true); - - BISpecifier[BufferedImage.TYPE_INT_BGR] = - createPacked(sRGB, - 0x000000ff, - 0x0000ff00, - 0x00ff0000, - 0x0, - DataBuffer.TYPE_INT, - false); - - int[] bOffsRGB = { 2, 1, 0 }; - BISpecifier[BufferedImage.TYPE_3BYTE_BGR] = - createInterleaved(sRGB, - bOffsRGB, - DataBuffer.TYPE_BYTE, - false, - false); - - int[] bOffsABGR = { 3, 2, 1, 0 }; - BISpecifier[BufferedImage.TYPE_4BYTE_ABGR] = - createInterleaved(sRGB, - bOffsABGR, - DataBuffer.TYPE_BYTE, - true, - false); - - BISpecifier[BufferedImage.TYPE_4BYTE_ABGR_PRE] = - createInterleaved(sRGB, - bOffsABGR, - DataBuffer.TYPE_BYTE, - true, - true); - - BISpecifier[BufferedImage.TYPE_USHORT_565_RGB] = - createPacked(sRGB, - 0xF800, - 0x07E0, - 0x001F, - 0x0, - DataBuffer.TYPE_USHORT, - false); - - BISpecifier[BufferedImage.TYPE_USHORT_555_RGB] = - createPacked(sRGB, - 0x7C00, - 0x03E0, - 0x001F, - 0x0, - DataBuffer.TYPE_USHORT, - false); - - BISpecifier[BufferedImage.TYPE_BYTE_GRAY] = - createGrayscale(8, - DataBuffer.TYPE_BYTE, - false); - - BISpecifier[BufferedImage.TYPE_USHORT_GRAY] = - createGrayscale(16, - DataBuffer.TYPE_USHORT, - false); - - BISpecifier[BufferedImage.TYPE_BYTE_BINARY] = - createGrayscale(1, - DataBuffer.TYPE_BYTE, - false); - - BufferedImage bi = - new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_INDEXED); - IndexColorModel icm = (IndexColorModel)bi.getColorModel(); - int mapSize = icm.getMapSize(); - byte[] redLUT = new byte[mapSize]; - byte[] greenLUT = new byte[mapSize]; - byte[] blueLUT = new byte[mapSize]; - byte[] alphaLUT = new byte[mapSize]; - - icm.getReds(redLUT); - icm.getGreens(greenLUT); - icm.getBlues(blueLUT); - icm.getAlphas(alphaLUT); - - BISpecifier[BufferedImage.TYPE_BYTE_INDEXED] = - createIndexed(redLUT, greenLUT, blueLUT, alphaLUT, - 8, - DataBuffer.TYPE_BYTE); } /** @@ -1011,7 +898,7 @@ public class ImageTypeSpecifier { ImageTypeSpecifier createFromBufferedImageType(int bufferedImageType) { if (bufferedImageType >= BufferedImage.TYPE_INT_RGB && bufferedImageType <= BufferedImage.TYPE_BYTE_INDEXED) { - return BISpecifier[bufferedImageType]; + return getSpecifier(bufferedImageType); } else if (bufferedImageType == BufferedImage.TYPE_CUSTOM) { throw new IllegalArgumentException("Cannot create from TYPE_CUSTOM!"); } else { @@ -1041,7 +928,7 @@ public class ImageTypeSpecifier { if (image instanceof BufferedImage) { int bufferedImageType = ((BufferedImage)image).getType(); if (bufferedImageType != BufferedImage.TYPE_CUSTOM) { - return BISpecifier[bufferedImageType]; + return getSpecifier(bufferedImageType); } } @@ -1225,4 +1112,130 @@ public class ImageTypeSpecifier { public int hashCode() { return (9 * colorModel.hashCode()) + (14 * sampleModel.hashCode()); } + + private static ImageTypeSpecifier getSpecifier(int type) { + if (BISpecifier[type] == null) { + BISpecifier[type] = createSpecifier(type); + } + return BISpecifier[type]; + } + + private static ImageTypeSpecifier createSpecifier(int type) { + switch(type) { + case BufferedImage.TYPE_INT_RGB: + return createPacked(sRGB, + 0x00ff0000, + 0x0000ff00, + 0x000000ff, + 0x0, + DataBuffer.TYPE_INT, + false); + + case BufferedImage.TYPE_INT_ARGB: + return createPacked(sRGB, + 0x00ff0000, + 0x0000ff00, + 0x000000ff, + 0xff000000, + DataBuffer.TYPE_INT, + false); + + case BufferedImage.TYPE_INT_ARGB_PRE: + return createPacked(sRGB, + 0x00ff0000, + 0x0000ff00, + 0x000000ff, + 0xff000000, + DataBuffer.TYPE_INT, + true); + + case BufferedImage.TYPE_INT_BGR: + return createPacked(sRGB, + 0x000000ff, + 0x0000ff00, + 0x00ff0000, + 0x0, + DataBuffer.TYPE_INT, + false); + + case BufferedImage.TYPE_3BYTE_BGR: + return createInterleaved(sRGB, + new int[] { 2, 1, 0 }, + DataBuffer.TYPE_BYTE, + false, + false); + + case BufferedImage.TYPE_4BYTE_ABGR: + return createInterleaved(sRGB, + new int[] { 3, 2, 1, 0 }, + DataBuffer.TYPE_BYTE, + true, + false); + + case BufferedImage.TYPE_4BYTE_ABGR_PRE: + return createInterleaved(sRGB, + new int[] { 3, 2, 1, 0 }, + DataBuffer.TYPE_BYTE, + true, + true); + + case BufferedImage.TYPE_USHORT_565_RGB: + return createPacked(sRGB, + 0xF800, + 0x07E0, + 0x001F, + 0x0, + DataBuffer.TYPE_USHORT, + false); + + case BufferedImage.TYPE_USHORT_555_RGB: + return createPacked(sRGB, + 0x7C00, + 0x03E0, + 0x001F, + 0x0, + DataBuffer.TYPE_USHORT, + false); + + case BufferedImage.TYPE_BYTE_GRAY: + return createGrayscale(8, + DataBuffer.TYPE_BYTE, + false); + + case BufferedImage.TYPE_USHORT_GRAY: + return createGrayscale(16, + DataBuffer.TYPE_USHORT, + false); + + case BufferedImage.TYPE_BYTE_BINARY: + return createGrayscale(1, + DataBuffer.TYPE_BYTE, + false); + + case BufferedImage.TYPE_BYTE_INDEXED: + { + + BufferedImage bi = + new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_INDEXED); + IndexColorModel icm = (IndexColorModel)bi.getColorModel(); + int mapSize = icm.getMapSize(); + byte[] redLUT = new byte[mapSize]; + byte[] greenLUT = new byte[mapSize]; + byte[] blueLUT = new byte[mapSize]; + byte[] alphaLUT = new byte[mapSize]; + + icm.getReds(redLUT); + icm.getGreens(greenLUT); + icm.getBlues(blueLUT); + icm.getAlphas(alphaLUT); + + return createIndexed(redLUT, greenLUT, blueLUT, alphaLUT, + 8, + DataBuffer.TYPE_BYTE); + } + default: + throw new IllegalArgumentException("Invalid BufferedImage type!"); + } + } + } From 454a7c0732e7b5c5bfd1e45a4ff6ef5e9c394438 Mon Sep 17 00:00:00 2001 From: Andrew Brygin Date: Fri, 30 Jan 2009 22:30:32 +0300 Subject: [PATCH 15/75] 6791502: IIOException "Invalid icc profile" on jpeg after update from JDK5 to JDK6 Reviewed-by: igor, prr --- .../native/sun/awt/image/jpeg/imageioJPEG.c | 112 +++++++++++------- 1 file changed, 70 insertions(+), 42 deletions(-) diff --git a/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c b/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c index 8c30b5ce69e..0a99c3fdb93 100644 --- a/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c +++ b/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c @@ -396,7 +396,7 @@ static imageIODataPtr initImageioData (JNIEnv *env, data->jpegObj = cinfo; cinfo->client_data = data; -#ifdef DEBUG +#ifdef DEBUG_IIO_JPEG printf("new structures: data is %p, cinfo is %p\n", data, cinfo); #endif @@ -673,7 +673,7 @@ static int setQTables(JNIEnv *env, j_decompress_ptr decomp; qlen = (*env)->GetArrayLength(env, qtables); -#ifdef DEBUG +#ifdef DEBUG_IIO_JPEG printf("in setQTables, qlen = %d, write is %d\n", qlen, write); #endif for (i = 0; i < qlen; i++) { @@ -876,7 +876,7 @@ imageio_fill_input_buffer(j_decompress_ptr cinfo) return FALSE; } -#ifdef DEBUG +#ifdef DEBUG_IIO_JPEG printf("Filling input buffer, remaining skip is %ld, ", sb->remaining_skip); printf("Buffer length is %d\n", sb->bufferLength); @@ -906,7 +906,7 @@ imageio_fill_input_buffer(j_decompress_ptr cinfo) cinfo->err->error_exit((j_common_ptr) cinfo); } -#ifdef DEBUG +#ifdef DEBUG_IIO_JPEG printf("Buffer filled. ret = %d\n", ret); #endif /* @@ -917,7 +917,7 @@ imageio_fill_input_buffer(j_decompress_ptr cinfo) */ if (ret <= 0) { jobject reader = data->imageIOobj; -#ifdef DEBUG +#ifdef DEBUG_IIO_JPEG printf("YO! Early EOI! ret = %d\n", ret); #endif RELEASE_ARRAYS(env, data, src->next_input_byte); @@ -1216,21 +1216,24 @@ read_icc_profile (JNIEnv *env, j_decompress_ptr cinfo) { jpeg_saved_marker_ptr marker; int num_markers = 0; + int num_found_markers = 0; int seq_no; JOCTET *icc_data; + JOCTET *dst_ptr; unsigned int total_length; #define MAX_SEQ_NO 255 // sufficient since marker numbers are bytes - char marker_present[MAX_SEQ_NO+1]; // 1 if marker found - unsigned int data_length[MAX_SEQ_NO+1]; // size of profile data in marker - unsigned int data_offset[MAX_SEQ_NO+1]; // offset for data in marker + jpeg_saved_marker_ptr icc_markers[MAX_SEQ_NO + 1]; + int first; // index of the first marker in the icc_markers array + int last; // index of the last marker in the icc_markers array jbyteArray data = NULL; /* This first pass over the saved markers discovers whether there are * any ICC markers and verifies the consistency of the marker numbering. */ - for (seq_no = 1; seq_no <= MAX_SEQ_NO; seq_no++) - marker_present[seq_no] = 0; + for (seq_no = 0; seq_no <= MAX_SEQ_NO; seq_no++) + icc_markers[seq_no] = NULL; + for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) { if (marker_is_icc(marker)) { @@ -1242,37 +1245,58 @@ read_icc_profile (JNIEnv *env, j_decompress_ptr cinfo) return NULL; } seq_no = GETJOCTET(marker->data[12]); - if (seq_no <= 0 || seq_no > num_markers) { + + /* Some third-party tools produce images with profile chunk + * numeration started from zero. It is inconsistent with ICC + * spec, but seems to be recognized by majority of image + * processing tools, so we should be more tolerant to this + * departure from the spec. + */ + if (seq_no < 0 || seq_no > num_markers) { JNU_ThrowByName(env, "javax/imageio/IIOException", "Invalid icc profile: bad sequence number"); return NULL; } - if (marker_present[seq_no]) { + if (icc_markers[seq_no] != NULL) { JNU_ThrowByName(env, "javax/imageio/IIOException", "Invalid icc profile: duplicate sequence numbers"); return NULL; } - marker_present[seq_no] = 1; - data_length[seq_no] = marker->data_length - ICC_OVERHEAD_LEN; + icc_markers[seq_no] = marker; + num_found_markers ++; } } if (num_markers == 0) return NULL; // There is no profile - /* Check for missing markers, count total space needed, - * compute offset of each marker's part of the data. - */ + if (num_markers != num_found_markers) { + JNU_ThrowByName(env, "javax/imageio/IIOException", + "Invalid icc profile: invalid number of icc markers"); + return NULL; + } + first = icc_markers[0] ? 0 : 1; + last = num_found_markers + first; + + /* Check for missing markers, count total space needed. + */ total_length = 0; - for (seq_no = 1; seq_no <= num_markers; seq_no++) { - if (marker_present[seq_no] == 0) { + for (seq_no = first; seq_no < last; seq_no++) { + unsigned int length; + if (icc_markers[seq_no] == NULL) { JNU_ThrowByName(env, "javax/imageio/IIOException", "Invalid icc profile: missing sequence number"); return NULL; } - data_offset[seq_no] = total_length; - total_length += data_length[seq_no]; + /* check the data length correctness */ + length = icc_markers[seq_no]->data_length; + if (ICC_OVERHEAD_LEN > length || length > MAX_BYTES_IN_MARKER) { + JNU_ThrowByName(env, "javax/imageio/IIOException", + "Invalid icc profile: invalid data length"); + return NULL; + } + total_length += (length - ICC_OVERHEAD_LEN); } if (total_length <= 0) { @@ -1301,19 +1325,14 @@ read_icc_profile (JNIEnv *env, j_decompress_ptr cinfo) } /* and fill it in */ - for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) { - if (marker_is_icc(marker)) { - JOCTET FAR *src_ptr; - JOCTET *dst_ptr; - unsigned int length; - seq_no = GETJOCTET(marker->data[12]); - dst_ptr = icc_data + data_offset[seq_no]; - src_ptr = marker->data + ICC_OVERHEAD_LEN; - length = data_length[seq_no]; - while (length--) { - *dst_ptr++ = *src_ptr++; - } - } + dst_ptr = icc_data; + for (seq_no = first; seq_no < last; seq_no++) { + JOCTET FAR *src_ptr = icc_markers[seq_no]->data + ICC_OVERHEAD_LEN; + unsigned int length = + icc_markers[seq_no]->data_length - ICC_OVERHEAD_LEN; + + memcpy(dst_ptr, src_ptr, length); + dst_ptr += length; } /* finally, unpin the array */ @@ -1530,6 +1549,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImageHeader j_decompress_ptr cinfo; struct jpeg_source_mgr *src; sun_jpeg_error_ptr jerr; + jbyteArray profileData = NULL; if (data == NULL) { JNU_ThrowByName(env, @@ -1557,7 +1577,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImageHeader return retval; } -#ifdef DEBUG +#ifdef DEBUG_IIO_JPEG printf("In readImageHeader, data is %p cinfo is %p\n", data, cinfo); printf("clearFirst is %d\n", clearFirst); #endif @@ -1584,7 +1604,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImageHeader if (ret == JPEG_HEADER_TABLES_ONLY) { retval = JNI_TRUE; imageio_term_source(cinfo); // Pushback remaining buffer contents -#ifdef DEBUG +#ifdef DEBUG_IIO_JPEG printf("just read tables-only image; q table 0 at %p\n", cinfo->quant_tbl_ptrs[0]); #endif @@ -1691,6 +1711,14 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImageHeader } } RELEASE_ARRAYS(env, data, src->next_input_byte); + + /* read icc profile data */ + profileData = read_icc_profile(env, cinfo); + + if ((*env)->ExceptionCheck(env)) { + return retval; + } + (*env)->CallVoidMethod(env, this, JPEGImageReader_setImageDataID, cinfo->image_width, @@ -1698,7 +1726,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImageHeader cinfo->jpeg_color_space, cinfo->out_color_space, cinfo->num_components, - read_icc_profile(env, cinfo)); + profileData); if (reset) { jpeg_abort_decompress(cinfo); } @@ -1827,7 +1855,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImage (*env)->ReleaseIntArrayElements(env, srcBands, body, JNI_ABORT); -#ifdef DEBUG +#ifdef DEBUG_IIO_JPEG printf("---- in reader.read ----\n"); printf("numBands is %d\n", numBands); printf("bands array: "); @@ -2487,7 +2515,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeTables data->streamBuf.suspendable = FALSE; if (qtables != NULL) { -#ifdef DEBUG +#ifdef DEBUG_IIO_JPEG printf("in writeTables: qtables not NULL\n"); #endif setQTables(env, (j_common_ptr) cinfo, qtables, TRUE); @@ -2763,7 +2791,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeImage cinfo->restart_interval = restartInterval; -#ifdef DEBUG +#ifdef DEBUG_IIO_JPEG printf("writer setup complete, starting compressor\n"); #endif @@ -2812,13 +2840,13 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeImage for (i = 0; i < numBands; i++) { if (scale !=NULL && scale[i] != NULL) { *out++ = scale[i][*(in+i)]; -#ifdef DEBUG +#ifdef DEBUG_IIO_JPEG if (in == data->pixelBuf.buf.bp){ // Just the first pixel printf("in %d -> out %d, ", *(in+i), *(out-i-1)); } #endif -#ifdef DEBUG +#ifdef DEBUG_IIO_JPEG if (in == data->pixelBuf.buf.bp){ // Just the first pixel printf("\n"); } From b56f07314820fea8178028ee1b80ea6a924bd2e1 Mon Sep 17 00:00:00 2001 From: Andrew Brygin Date: Wed, 4 Feb 2009 14:06:18 +0300 Subject: [PATCH 16/75] 6799583: LogManager shutdown hook may cause a memory leak Reviewed-by: igor, swamyv --- .../classes/java/util/logging/LogManager.java | 8 + .../util/logging/ClassLoaderLeakTest.java | 190 ++++++++++++++++++ 2 files changed, 198 insertions(+) create mode 100644 jdk/test/java/util/logging/ClassLoaderLeakTest.java diff --git a/jdk/src/share/classes/java/util/logging/LogManager.java b/jdk/src/share/classes/java/util/logging/LogManager.java index 412f749404d..fc8f080eb71 100644 --- a/jdk/src/share/classes/java/util/logging/LogManager.java +++ b/jdk/src/share/classes/java/util/logging/LogManager.java @@ -215,6 +215,14 @@ public class LogManager { // This private class is used as a shutdown hook. // It does a "reset" to close all open handlers. private class Cleaner extends Thread { + + private Cleaner() { + /* Set context class loader to null in order to avoid + * keeping a strong reference to an application classloader. + */ + this.setContextClassLoader(null); + } + public void run() { // This is to ensure the LogManager. is completed // before synchronized block. Otherwise deadlocks are possible. diff --git a/jdk/test/java/util/logging/ClassLoaderLeakTest.java b/jdk/test/java/util/logging/ClassLoaderLeakTest.java new file mode 100644 index 00000000000..988041472fc --- /dev/null +++ b/jdk/test/java/util/logging/ClassLoaderLeakTest.java @@ -0,0 +1,190 @@ +/* + * 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 6799583 + * + * @summary Test verifes that LogManager shutdown hook does not cause + * an application classloader leaks. + * + * @run main/othervm ClassLoaderLeakTest + */ + +import java.io.File; +import java.lang.ref.WeakReference; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.concurrent.CountDownLatch; +import java.util.logging.Logger; +import java.util.logging.Logger; + +public class ClassLoaderLeakTest { + + private static CountDownLatch doneSignal; + private static CountDownLatch launchSignal; + private static ThreadGroup appsThreadGroup; + private static Throwable launchFailure = null; + + public static void main(String[] args) { + appsThreadGroup = new ThreadGroup("MyAppsThreadGroup"); + doneSignal = new CountDownLatch(1); + launchSignal = new CountDownLatch(1); + + Runnable launcher = new Runnable() { + public void run() { + try { + ClassLoader cl = + Thread.currentThread().getContextClassLoader(); + Class appMain = cl.loadClass("AppTest"); + Method launch = + appMain.getDeclaredMethod("launch", doneSignal.getClass()); + + Constructor c = appMain.getConstructor(); + + Object o = c.newInstance(); + + launch.invoke(o, doneSignal); + + } catch (Throwable e) { + launchFailure = e; + } finally { + launchSignal.countDown(); + } + } + }; + + /* prepare test class loader */ + URL pwd = null; + try { + + pwd = new File(System.getProperty("test.classes",".")).toURL(); + } catch (MalformedURLException e) { + throw new RuntimeException("Test failed.", e); + } + URL[] urls = new URL[] { pwd }; + + MyClassLoader appClassLoader = new MyClassLoader(urls, "test0"); + WeakReference ref = + new WeakReference(appClassLoader); + + + Thread appThread = new Thread(appsThreadGroup, launcher, "AppThread-0"); + appThread.setContextClassLoader(appClassLoader); + + appThread.start(); + appClassLoader = null; + launcher = null; + appThread = null; + + /* wait for laucnh completion */ + try { + launchSignal.await(); + } catch (InterruptedException e) { + } + + /* check if launch failed */ + if (launchFailure != null) { + throw new RuntimeException("Test failed.", launchFailure); + } + + /* wait for test app excution completion */ + try { + doneSignal.await(); + } catch (InterruptedException e) { + } + + /* give a chence to GC */ + waitAndGC(5); + + if (ref.get() != null) { + throw new RuntimeException("Test failed: classloader is still alive"); + } + + System.out.println("Test passed."); + } + + private static class MyClassLoader extends URLClassLoader { + + private static boolean verbose = + Boolean.getBoolean("verboseClassLoading"); + private String uniqClassName; + + public MyClassLoader(URL[] urls, String uniq) { + super(urls); + + uniqClassName = uniq; + } + + public Class loadClass(String name) throws ClassNotFoundException { + if (verbose) { + System.out.printf("%s: load class %s\n", uniqClassName, name); + } + if (uniqClassName.equals(name)) { + return Object.class; + } + return super.loadClass(name); + } + + public String toString() { + return "MyClassLoader(" + uniqClassName + ")"; + } + } + + private static void waitAndGC(int sec) { + int cnt = sec; + System.out.print("Wait "); + while (cnt-- > 0) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + // do GC every 3 seconds + if (cnt % 3 == 2) { + System.gc(); + System.out.print("+"); + } else { + System.out.print("."); + } + //checkErrors(); + } + System.out.println(""); + } +} + + +class AppTest { + public AppTest() { + + } + + public void launch(CountDownLatch done) { + Logger log = Logger.getLogger("app_test_logger"); + log.fine("Test app is launched"); + + done.countDown(); + } +} From d83e26cba476db741b0638154ae0d2d922fe91f9 Mon Sep 17 00:00:00 2001 From: Andrew Brygin Date: Fri, 6 Feb 2009 20:49:53 +0300 Subject: [PATCH 17/75] 6800846: REGRESSION: Printing quality degraded with Java 6 compared to 5.0 Reviewed-by: igor, prr --- jdk/src/share/native/sun/awt/image/dither.c | 11 +-- jdk/test/sun/awt/image/DrawByteBinary.java | 75 +++++++++++++++++++++ 2 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 jdk/test/sun/awt/image/DrawByteBinary.java diff --git a/jdk/src/share/native/sun/awt/image/dither.c b/jdk/src/share/native/sun/awt/image/dither.c index a935d6766f6..cb2303e76d7 100644 --- a/jdk/src/share/native/sun/awt/image/dither.c +++ b/jdk/src/share/native/sun/awt/image/dither.c @@ -169,6 +169,7 @@ initCubemap(int* cmap, int cubesize = cube_dim * cube_dim * cube_dim; unsigned char *useFlags; unsigned char *newILut = (unsigned char*)malloc(cubesize); + int cmap_mid = (cmap_len >> 1) + (cmap_len & 0x1); if (newILut) { useFlags = (unsigned char *)calloc(cubesize, 1); @@ -188,7 +189,7 @@ initCubemap(int* cmap, currentState.iLUT = newILut; currentState.rgb = (unsigned short *) - malloc(256 * sizeof(unsigned short)); + malloc(cmap_len * sizeof(unsigned short)); if (currentState.rgb == NULL) { free(newILut); free(useFlags); @@ -199,7 +200,7 @@ initCubemap(int* cmap, } currentState.indices = (unsigned char *) - malloc(256 * sizeof(unsigned char)); + malloc(cmap_len * sizeof(unsigned char)); if (currentState.indices == NULL) { free(currentState.rgb); free(newILut); @@ -210,18 +211,18 @@ initCubemap(int* cmap, return NULL; } - for (i = 0; i < 128; i++) { + for (i = 0; i < cmap_mid; i++) { unsigned short rgb; int pixel = cmap[i]; rgb = (pixel & 0x00f80000) >> 9; rgb |= (pixel & 0x0000f800) >> 6; rgb |= (pixel & 0xf8) >> 3; INSERTNEW(currentState, rgb, i); - pixel = cmap[255-i]; + pixel = cmap[cmap_len - i - 1]; rgb = (pixel & 0x00f80000) >> 9; rgb |= (pixel & 0x0000f800) >> 6; rgb |= (pixel & 0xf8) >> 3; - INSERTNEW(currentState, rgb, 255-i); + INSERTNEW(currentState, rgb, cmap_len - i - 1); } if (!recurseLevel(¤tState)) { diff --git a/jdk/test/sun/awt/image/DrawByteBinary.java b/jdk/test/sun/awt/image/DrawByteBinary.java new file mode 100644 index 00000000000..e9db5c63f23 --- /dev/null +++ b/jdk/test/sun/awt/image/DrawByteBinary.java @@ -0,0 +1,75 @@ +/* + * 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 6800846 + * + * @summary Test verifes that images with short palette are rendered + * withourt artifacts. + * + * @run main DrawByteBinary + */ + + +import java.awt.*; +import java.awt.color.*; +import java.awt.image.*; +import static java.awt.image.BufferedImage.*; + + +public class DrawByteBinary { + + public static void main(String args[]) { + int w = 100, h = 30; + int x = 10; + byte[] arr = {(byte)0xff, (byte)0x0, (byte)0x00}; + + IndexColorModel newCM = new IndexColorModel(1, 2, arr, arr, arr); + BufferedImage orig = new BufferedImage(w, h, TYPE_BYTE_BINARY, newCM); + Graphics2D g2d = orig.createGraphics(); + g2d.setColor(Color.white); + g2d.fillRect(0, 0, w, h); + g2d.setColor(Color.black); + g2d.drawLine(x, 0, x, h); + g2d.dispose(); + + IndexColorModel origCM = (IndexColorModel)orig.getColorModel(); + BufferedImage test = new BufferedImage(w, h, TYPE_BYTE_BINARY,origCM); + g2d = test.createGraphics(); + g2d.drawImage(orig, 0, 0, null); + g2d.dispose(); + + int y = h / 2; + + // we expect white color outside the line + if (test.getRGB(x - 1, y) != 0xffffffff) { + throw new RuntimeException("Invalid color outside the line."); + } + + // we expect black color on the line + if (test.getRGB(x, y) != 0xff000000) { + throw new RuntimeException("Invalid color on the line."); + } + } +} From 34f01f340ef747ada113f4002f2f6b2e992678aa Mon Sep 17 00:00:00 2001 From: Jennifer Godinez Date: Tue, 24 Feb 2009 14:32:17 -0800 Subject: [PATCH 18/75] 6750383: 2D_PrintingTiger\PrintDocOrientationTest fails, wrong orientated images are printed Reviewed-by: campbell, prr --- jdk/src/solaris/classes/sun/print/IPPPrintService.java | 6 ++++++ jdk/src/solaris/classes/sun/print/UnixPrintJob.java | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/jdk/src/solaris/classes/sun/print/IPPPrintService.java b/jdk/src/solaris/classes/sun/print/IPPPrintService.java index 07b68b18fa8..ec5344ae379 100644 --- a/jdk/src/solaris/classes/sun/print/IPPPrintService.java +++ b/jdk/src/solaris/classes/sun/print/IPPPrintService.java @@ -661,6 +661,12 @@ public class IPPPrintService implements PrintService, SunPrinterJobService { } } } else if (category == OrientationRequested.class) { + if (flavor.equals(DocFlavor.INPUT_STREAM.POSTSCRIPT) || + flavor.equals(DocFlavor.URL.POSTSCRIPT) || + flavor.equals(DocFlavor.BYTE_ARRAY.POSTSCRIPT)) { + return null; + } + boolean revPort = false; OrientationRequested[] orientSup = null; diff --git a/jdk/src/solaris/classes/sun/print/UnixPrintJob.java b/jdk/src/solaris/classes/sun/print/UnixPrintJob.java index 1a96e92f2c8..b4da652a8fc 100644 --- a/jdk/src/solaris/classes/sun/print/UnixPrintJob.java +++ b/jdk/src/solaris/classes/sun/print/UnixPrintJob.java @@ -362,10 +362,10 @@ public class UnixPrintJob implements CancelablePrintJob { mOptions += " number-up="+nUp.getValue(); } - if (orient == OrientationRequested.LANDSCAPE && + if (orient != OrientationRequested.PORTRAIT && (flavor != null) && !flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE)) { - mOptions += " landscape"; + mOptions += " orientation-requested="+orient.getValue(); } if (sides != null) { From 4fd14806a47371139817f7e496da823066954fd1 Mon Sep 17 00:00:00 2001 From: Clemens Eisserer Date: Thu, 26 Feb 2009 13:38:38 -0800 Subject: [PATCH 19/75] 6791612: OGLBat tests are failed in jdk 7 b42 Reviewed-by: tdv --- jdk/make/sun/xawt/mapfile-vers | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jdk/make/sun/xawt/mapfile-vers b/jdk/make/sun/xawt/mapfile-vers index d4b5b6e32ba..07b16cefcc8 100644 --- a/jdk/make/sun/xawt/mapfile-vers +++ b/jdk/make/sun/xawt/mapfile-vers @@ -302,12 +302,14 @@ SUNWprivate_1.1 { Java_java_awt_FileDialog_initIDs; Java_sun_awt_X11_XWindow_initIDs; + Java_sun_java2d_opengl_OGLContext_getOGLIdString; Java_sun_java2d_opengl_OGLMaskFill_maskFill; Java_sun_java2d_opengl_OGLRenderer_drawPoly; Java_sun_java2d_opengl_OGLRenderQueue_flushBuffer; Java_sun_java2d_opengl_OGLSurfaceData_initTexture; Java_sun_java2d_opengl_OGLSurfaceData_initFBObject; Java_sun_java2d_opengl_OGLSurfaceData_initFlipBackbuffer; + Java_sun_java2d_opengl_OGLSurfaceData_getTextureID; Java_sun_java2d_opengl_OGLSurfaceData_getTextureTarget; Java_sun_java2d_opengl_OGLTextRenderer_drawGlyphList; Java_sun_java2d_opengl_GLXGraphicsConfig_getGLXConfigInfo; From c9de141417c937a3f73c651d459c270df16dff05 Mon Sep 17 00:00:00 2001 From: Jennifer Godinez Date: Thu, 5 Mar 2009 10:56:06 -0800 Subject: [PATCH 20/75] 6735296: Regression: Common print dialog does not show the correct page orientation Reviewed-by: tdv, prr --- .../classes/sun/print/ServiceDialog.java | 76 +++++++++---------- 1 file changed, 36 insertions(+), 40 deletions(-) diff --git a/jdk/src/share/classes/sun/print/ServiceDialog.java b/jdk/src/share/classes/sun/print/ServiceDialog.java index 8b5bd478900..062e6163a6f 100644 --- a/jdk/src/share/classes/sun/print/ServiceDialog.java +++ b/jdk/src/share/classes/sun/print/ServiceDialog.java @@ -2149,55 +2149,51 @@ public class ServiceDialog extends JDialog implements ActionListener { } } } + } - rbPortrait.setEnabled(pSupported); - rbLandscape.setEnabled(lSupported); - rbRevPortrait.setEnabled(rpSupported); - rbRevLandscape.setEnabled(rlSupported); - OrientationRequested or = (OrientationRequested)asCurrent.get(orCategory); - if (or == null || - !psCurrent.isAttributeValueSupported(or, docFlavor, asCurrent)) { + rbPortrait.setEnabled(pSupported); + rbLandscape.setEnabled(lSupported); + rbRevPortrait.setEnabled(rpSupported); + rbRevLandscape.setEnabled(rlSupported); - or = (OrientationRequested)psCurrent.getDefaultAttributeValue(orCategory); - // need to validate if default is not supported - if (!psCurrent.isAttributeValueSupported(or, docFlavor, asCurrent)) { - or = null; - values = - psCurrent.getSupportedAttributeValues(orCategory, - docFlavor, - asCurrent); - if (values instanceof OrientationRequested[]) { - OrientationRequested[] orValues = - (OrientationRequested[])values; - if (orValues.length > 1) { - // get the first in the list - or = orValues[0]; - } + OrientationRequested or = (OrientationRequested)asCurrent.get(orCategory); + if (or == null || + !psCurrent.isAttributeValueSupported(or, docFlavor, asCurrent)) { + + or = (OrientationRequested)psCurrent.getDefaultAttributeValue(orCategory); + // need to validate if default is not supported + if ((or != null) && + !psCurrent.isAttributeValueSupported(or, docFlavor, asCurrent)) { + or = null; + Object values = + psCurrent.getSupportedAttributeValues(orCategory, + docFlavor, + asCurrent); + if (values instanceof OrientationRequested[]) { + OrientationRequested[] orValues = + (OrientationRequested[])values; + if (orValues.length > 1) { + // get the first in the list + or = orValues[0]; } } - - if (or == null) { - or = OrientationRequested.PORTRAIT; - } - asCurrent.add(or); } - if (or == OrientationRequested.PORTRAIT) { - rbPortrait.setSelected(true); - } else if (or == OrientationRequested.LANDSCAPE) { - rbLandscape.setSelected(true); - } else if (or == OrientationRequested.REVERSE_PORTRAIT) { - rbRevPortrait.setSelected(true); - } else { // if (or == OrientationRequested.REVERSE_LANDSCAPE) - rbRevLandscape.setSelected(true); + if (or == null) { + or = OrientationRequested.PORTRAIT; } - } else { - rbPortrait.setEnabled(pSupported); - rbLandscape.setEnabled(lSupported); - rbRevPortrait.setEnabled(rpSupported); - rbRevLandscape.setEnabled(rlSupported); + asCurrent.add(or); + } + if (or == OrientationRequested.PORTRAIT) { + rbPortrait.setSelected(true); + } else if (or == OrientationRequested.LANDSCAPE) { + rbLandscape.setSelected(true); + } else if (or == OrientationRequested.REVERSE_PORTRAIT) { + rbRevPortrait.setSelected(true); + } else { // if (or == OrientationRequested.REVERSE_LANDSCAPE) + rbRevLandscape.setSelected(true); } } } From e4661801352674f01f64ba70f4d735afab05a102 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Thu, 12 Mar 2009 15:36:14 +0100 Subject: [PATCH 21/75] 6661448: Make the SNMP agent optional when OPENJDK=true and IMPORT_BINARY_PLUGS=false Reviewed-by: mchung, ohair --- jdk/make/com/sun/jmx/Makefile | 10 +- jdk/make/java/management/Makefile | 2 + jdk/make/javax/management/Makefile | 1 + jdk/make/sun/management/Makefile | 11 +- .../share/classes/sun/management/Agent.java | 38 ++++- .../com/sun/jmx/snmp/SnmpOidHashCode.java | 74 ++++++++- .../com/sun/jmx/snmp/TimeTicksWrapping.java | 157 ++++++++++++++++-- 7 files changed, 268 insertions(+), 25 deletions(-) diff --git a/jdk/make/com/sun/jmx/Makefile b/jdk/make/com/sun/jmx/Makefile index c529dd4be31..81470f0befe 100644 --- a/jdk/make/com/sun/jmx/Makefile +++ b/jdk/make/com/sun/jmx/Makefile @@ -41,7 +41,15 @@ include $(BUILDDIR)/common/Defs.gmk # Note : some targets are double colon rules and some single colon rules # within common included gmk files : that is why the following for loop # has been duplicated. -SUBDIRS = snmp + +# When building the openjdk, build snmp only if importing binary plugs, +ifdef OPENJDK + ifeq ($(IMPORT_BINARY_PLUGS),true) + SUBDIRS = snmp + endif +else + SUBDIRS = snmp +endif all build: $(SUBDIRS-loop) diff --git a/jdk/make/java/management/Makefile b/jdk/make/java/management/Makefile index 466d2212afe..f579e10c105 100644 --- a/jdk/make/java/management/Makefile +++ b/jdk/make/java/management/Makefile @@ -46,6 +46,8 @@ include $(BUILDDIR)/common/Mapfile-vers.gmk # include FILES_c.gmk +# We don't need snmp here. +AUTO_JAVA_PRUNE = snmp AUTO_FILES_JAVA_DIRS = java/lang/management com/sun/management sun/management include Exportedfiles.gmk diff --git a/jdk/make/javax/management/Makefile b/jdk/make/javax/management/Makefile index 2085e38a88b..02527ec2d21 100644 --- a/jdk/make/javax/management/Makefile +++ b/jdk/make/javax/management/Makefile @@ -35,6 +35,7 @@ include $(BUILDDIR)/common/Defs.gmk # # Files to compile # +AUTO_JAVA_PRUNE = snmp AUTO_FILES_JAVA_DIRS = javax/management com/sun/jmx com/sun/management/jmx # diff --git a/jdk/make/sun/management/Makefile b/jdk/make/sun/management/Makefile index 6ae5d85d817..bb7ad8935c9 100644 --- a/jdk/make/sun/management/Makefile +++ b/jdk/make/sun/management/Makefile @@ -35,7 +35,16 @@ MGMT_LIB_SRC = $(SHARE_SRC)/lib/management all build:: properties aclfile jmxremotefiles -SUBDIRS = snmp jmxremote +# When building the openjdk, build snmp only if importing binary plugs, +ifdef OPENJDK + ifeq ($(IMPORT_BINARY_PLUGS),true) + SUBDIRS = snmp + endif +else + SUBDIRS = snmp +endif +SUBDIRS += jmxremote + all build clean clobber:: $(SUBDIRS-loop) diff --git a/jdk/src/share/classes/sun/management/Agent.java b/jdk/src/share/classes/sun/management/Agent.java index e247412ba91..edc53f93c6e 100644 --- a/jdk/src/share/classes/sun/management/Agent.java +++ b/jdk/src/share/classes/sun/management/Agent.java @@ -31,9 +31,9 @@ import java.io.FileInputStream; import java.io.BufferedInputStream; import java.io.FileNotFoundException; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; import java.text.MessageFormat; import java.util.Properties; -import java.util.Enumeration; import java.util.ResourceBundle; import java.util.MissingResourceException; import java.lang.management.ManagementFactory; @@ -41,7 +41,6 @@ import java.lang.reflect.Method; import javax.management.remote.JMXConnectorServer; -import sun.management.snmp.AdaptorBootstrap; import sun.management.jmxremote.ConnectorBootstrap; import static sun.management.AgentConfigurationError.*; import sun.misc.VMSupport; @@ -69,6 +68,9 @@ public class Agent { private static final String LOCAL_CONNECTOR_ADDRESS_PROP = "com.sun.management.jmxremote.localConnectorAddress"; + private static final String SNMP_ADAPTOR_BOOTSTRAP_CLASS_NAME = + "sun.management.snmp.AdaptorBootstrap"; + // invoked by -javaagent or -Dcom.sun.management.agent.class public static void premain(String args) throws Exception { agentmain(args); @@ -128,7 +130,7 @@ public class Agent { try { if (snmpPort != null) { - AdaptorBootstrap.initialize(snmpPort, props); + loadSnmpAgent(snmpPort, props); } /* @@ -204,6 +206,36 @@ public class Agent { return mgmtProps; } + private static void loadSnmpAgent(String snmpPort, Properties props) { + try { + // invoke the following through reflection: + // AdaptorBootstrap.initialize(snmpPort, props); + final Class adaptorClass = + Class.forName(SNMP_ADAPTOR_BOOTSTRAP_CLASS_NAME,true,null); + final Method initializeMethod = + adaptorClass.getMethod("initialize", + String.class, Properties.class); + initializeMethod.invoke(null,snmpPort,props); + } catch (ClassNotFoundException x) { + // The SNMP packages are not present: throws an exception. + throw new UnsupportedOperationException("Unsupported management property: " + SNMP_PORT,x); + } catch (NoSuchMethodException x) { + // should not happen... + throw new UnsupportedOperationException("Unsupported management property: " + SNMP_PORT,x); + } catch (InvocationTargetException x) { + final Throwable cause = x.getCause(); + if (cause instanceof RuntimeException) + throw (RuntimeException) cause; + else if (cause instanceof Error) + throw (Error) cause; + // should not happen... + throw new UnsupportedOperationException("Unsupported management property: " + SNMP_PORT,cause); + } catch (IllegalAccessException x) { + // should not happen... + throw new UnsupportedOperationException("Unsupported management property: " + SNMP_PORT,x); + } + } + // read config file and initialize the properties private static void readConfiguration(String fname, Properties p) { if (fname == null) { diff --git a/jdk/test/com/sun/jmx/snmp/SnmpOidHashCode.java b/jdk/test/com/sun/jmx/snmp/SnmpOidHashCode.java index 907d00913f4..4a815de0386 100644 --- a/jdk/test/com/sun/jmx/snmp/SnmpOidHashCode.java +++ b/jdk/test/com/sun/jmx/snmp/SnmpOidHashCode.java @@ -1,5 +1,5 @@ /* - * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 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 @@ -28,7 +28,8 @@ * @build SnmpOidHashCode * @run main SnmpOidHashCode */ -import com.sun.jmx.snmp.SnmpOid; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; public class SnmpOidHashCode { public static final String[] oids = { @@ -57,16 +58,81 @@ public class SnmpOidHashCode { ".39."+0xFFFFFFFFL }; + // We use an SnmpOidBuilder in order to adapt this test case to a + // configuration where the SNMP packages are not present in rt.jar. + // + public static final class SnmpOidBuilder { + public static final String SNMP_OID_CLASS_NAME = + "com.sun.jmx.snmp.SnmpOid"; + private static final Class SNMP_OID_CLASS; + private static final Constructor SNMP_OID_CTOR; + static { + Class snmpOidClass; + try { + snmpOidClass = + Class.forName(SNMP_OID_CLASS_NAME, true, null); + } catch (ClassNotFoundException x) { + snmpOidClass = null; + System.err.println("WARNING: can't load "+SNMP_OID_CLASS_NAME); + } catch (NoClassDefFoundError x) { + snmpOidClass = null; + System.err.println("WARNING: can't load "+SNMP_OID_CLASS_NAME); + } + SNMP_OID_CLASS = snmpOidClass; + if (SNMP_OID_CLASS != null) { + try { + SNMP_OID_CTOR = snmpOidClass.getConstructor(String.class); + } catch (Exception x) { + throw new ExceptionInInitializerError(x); + } + } else { + SNMP_OID_CTOR = null; + } + } + + public static boolean isSnmpPresent() { + System.out.println(SnmpOidHashCode.class.getName()+ + ": Testing for SNMP Packages..."); + return SNMP_OID_CLASS != null; + } + + public static Object newSnmpOid(String oid) + throws InstantiationException, + IllegalAccessException, + InvocationTargetException { + return SNMP_OID_CTOR.newInstance(oid); + } + + } + + private static Object newSnmpOid(String oid) throws Exception { + try { + return SnmpOidBuilder.newSnmpOid(oid); + } catch (InvocationTargetException x) { + final Throwable cause = x.getCause(); + if (cause instanceof Exception) throw (Exception)cause; + if (cause instanceof Error) throw (Error)cause; + throw x; + } + } + public static void main(String args[]) { + if (!SnmpOidBuilder.isSnmpPresent()) { + System.err.println("WARNING: "+ + SnmpOidBuilder.SNMP_OID_CLASS_NAME+" not present."); + System.err.println(SnmpOidHashCode.class.getName()+ + ": test skipped."); + return; + } try { int errCount=0; int collisions=0; for (int i=0;i SNMP_TIME_TICKS_CLASS; + private static final Constructor SNMP_long_CTOR; + private static final Constructor SNMP_LONG_CTOR; + private static final Method SNMP_LONG_VALUE; + static { + Class snmpTimeTicksClass; + try { + snmpTimeTicksClass = + Class.forName(SNMP_TIME_TICKS_CLASS_NAME, true, null); + } catch (ClassNotFoundException x) { + snmpTimeTicksClass = null; + System.err.println("WARNING: can't load "+ + SNMP_TIME_TICKS_CLASS_NAME); + } catch (NoClassDefFoundError x) { + snmpTimeTicksClass = null; + System.err.println("WARNING: can't load "+ + SNMP_TIME_TICKS_CLASS_NAME); + } + SNMP_TIME_TICKS_CLASS = snmpTimeTicksClass; + if (SNMP_TIME_TICKS_CLASS != null) { + try { + SNMP_long_CTOR = + SNMP_TIME_TICKS_CLASS.getConstructor(long.class); + } catch (Exception x) { + throw new ExceptionInInitializerError(x); + } + } else { + SNMP_long_CTOR = null; + } + if (SNMP_TIME_TICKS_CLASS != null) { + try { + SNMP_LONG_CTOR = + SNMP_TIME_TICKS_CLASS.getConstructor(Long.class); + } catch (Exception x) { + throw new ExceptionInInitializerError(x); + } + } else { + SNMP_LONG_CTOR = null; + } + if (SNMP_TIME_TICKS_CLASS != null) { + try { + SNMP_LONG_VALUE = + SNMP_TIME_TICKS_CLASS.getMethod("longValue"); + } catch (Exception x) { + throw new ExceptionInInitializerError(x); + } + } else { + SNMP_LONG_VALUE = null; + } + + } + + private final Object timeticks; + + public SnmpTimeticksBuilder(long ticks) throws Exception { + timeticks = newSnmpTimeticks(ticks); + } + public SnmpTimeticksBuilder(Long ticks) throws Exception { + timeticks = newSnmpTimeticks(ticks); + } + public long longValue() throws Exception { + return longValue(timeticks); + } + + public static boolean isSnmpPresent() { + System.out.println(TimeTicksWrapping.class.getName()+ + ": Testing for SNMP Packages..."); + return SNMP_TIME_TICKS_CLASS != null; + } + + private static Object newSnmpTimeticks(long time) + throws Exception { + try { + return SNMP_long_CTOR.newInstance(time); + } catch (InvocationTargetException x) { + final Throwable cause = x.getCause(); + if (cause instanceof Exception) throw (Exception) cause; + if (cause instanceof Error) throw (Error) cause; + throw x; + } + } + + private static Object newSnmpTimeticks(Long time) + throws Exception { + try { + return SNMP_LONG_CTOR.newInstance(time); + } catch (InvocationTargetException x) { + final Throwable cause = x.getCause(); + if (cause instanceof Exception) throw (Exception) cause; + if (cause instanceof Error) throw (Error) cause; + throw x; + } + } + + private static long longValue(Object o) + throws Exception { + try { + return ((Long)SNMP_LONG_VALUE.invoke(o)).longValue(); + } catch (InvocationTargetException x) { + final Throwable cause = x.getCause(); + if (cause instanceof Exception) throw (Exception) cause; + if (cause instanceof Error) throw (Error) cause; + throw x; + } + } + + } + public static final long[] oks = { 0L, 1L, (long)Integer.MAX_VALUE, (long)Integer.MAX_VALUE*2, (long)Integer.MAX_VALUE*2+1L, (long)Integer.MAX_VALUE*2+2L, (long)Integer.MAX_VALUE*3, - SnmpUnsignedInt.MAX_VALUE, SnmpUnsignedInt.MAX_VALUE+1L, - SnmpUnsignedInt.MAX_VALUE*3-1L, Long.MAX_VALUE + SnmpTimeticksBuilder.MAX_VALUE, SnmpTimeticksBuilder.MAX_VALUE+1L, + SnmpTimeticksBuilder.MAX_VALUE*3-1L, Long.MAX_VALUE }; public static final long[] kos = { -1L, (long)Integer.MIN_VALUE, (long)Integer.MIN_VALUE*2, (long)Integer.MIN_VALUE*2-1L, (long)Integer.MIN_VALUE*3, - -SnmpUnsignedInt.MAX_VALUE, -(SnmpUnsignedInt.MAX_VALUE+1L), - -(SnmpUnsignedInt.MAX_VALUE*3-1L), Long.MIN_VALUE + -SnmpTimeticksBuilder.MAX_VALUE, -(SnmpTimeticksBuilder.MAX_VALUE+1L), + -(SnmpTimeticksBuilder.MAX_VALUE*3-1L), Long.MIN_VALUE }; + public static void main(String args[]) { + if (!SnmpTimeticksBuilder.isSnmpPresent()) { + System.err.println("WARNING: "+ + SnmpTimeticksBuilder.SNMP_TIME_TICKS_CLASS_NAME+ + " not present."); + System.err.println(TimeTicksWrapping.class.getName()+ + ": test skipped."); + return; + } try { - SnmpTimeticks t; + SnmpTimeticksBuilder t = null; for (int i=0;i SnmpUnsignedInt.MAX_VALUE) + if (t1 > SnmpTimeticksBuilder.MAX_VALUE) throw new Exception("Value should have wrapped " + "for " + oks[i] + ": " + t1 + " exceeds max: " + - SnmpUnsignedInt.MAX_VALUE); - if (t2 > SnmpUnsignedInt.MAX_VALUE) + SnmpTimeticksBuilder.MAX_VALUE); + if (t2 > SnmpTimeticksBuilder.MAX_VALUE) throw new Exception("Value should have wrapped " + "for " + oks[i] + ": " + t2 + " exceeds max: " + - SnmpUnsignedInt.MAX_VALUE); + SnmpTimeticksBuilder.MAX_VALUE); if (t1 < 0) throw new Exception("Value should have wrapped: " + @@ -90,14 +215,14 @@ public class TimeTicksWrapping { for (int i=0;i Date: Thu, 12 Mar 2009 10:27:22 -0700 Subject: [PATCH 22/75] 6810254: Lazily instantiate the shared secret access objects Register the shutdown hooks only when needed and remove JavaIODeleteOnExitAccess Reviewed-by: alanb --- jdk/make/java/java/FILES_java.gmk | 1 - jdk/src/share/classes/java/io/Console.java | 29 +++++++------- .../classes/java/io/DeleteOnExitHook.java | 19 +++++----- jdk/src/share/classes/java/io/File.java | 12 ------ .../java/lang/ApplicationShutdownHooks.java | 20 +++++----- jdk/src/share/classes/java/lang/Shutdown.java | 38 +++++++------------ jdk/src/share/classes/java/lang/System.java | 11 ++---- .../share/classes/sun/misc/JavaIOAccess.java | 1 - .../sun/misc/JavaIODeleteOnExitAccess.java | 30 --------------- .../classes/sun/misc/JavaLangAccess.java | 3 ++ .../share/classes/sun/misc/SharedSecrets.java | 12 ------ 11 files changed, 54 insertions(+), 122 deletions(-) delete mode 100644 jdk/src/share/classes/sun/misc/JavaIODeleteOnExitAccess.java diff --git a/jdk/make/java/java/FILES_java.gmk b/jdk/make/java/java/FILES_java.gmk index 3117af8461f..83f3af7d968 100644 --- a/jdk/make/java/java/FILES_java.gmk +++ b/jdk/make/java/java/FILES_java.gmk @@ -449,7 +449,6 @@ JAVA_JAVA_java = \ sun/misc/Service.java \ sun/misc/JavaLangAccess.java \ sun/misc/JavaIOAccess.java \ - sun/misc/JavaIODeleteOnExitAccess.java \ sun/misc/JavaIOFileDescriptorAccess.java \ sun/misc/JavaNioAccess.java diff --git a/jdk/src/share/classes/java/io/Console.java b/jdk/src/share/classes/java/io/Console.java index 9e009943a95..201b66f71b5 100644 --- a/jdk/src/share/classes/java/io/Console.java +++ b/jdk/src/share/classes/java/io/Console.java @@ -503,6 +503,21 @@ public final class Console implements Flushable // Set up JavaIOAccess in SharedSecrets static { + + // Add a shutdown hook to restore console's echo state should + // it be necessary. + sun.misc.SharedSecrets.getJavaLangAccess() + .registerShutdownHook(0 /* shutdown hook invocation order */, + new Runnable() { + public void run() { + try { + if (echoOff) { + echo(true); + } + } catch (IOException x) { } + } + }); + sun.misc.SharedSecrets.setJavaIOAccess(new sun.misc.JavaIOAccess() { public Console console() { if (istty()) { @@ -513,20 +528,6 @@ public final class Console implements Flushable return null; } - // Add a shutdown hook to restore console's echo state should - // it be necessary. - public Runnable consoleRestoreHook() { - return new Runnable() { - public void run() { - try { - if (echoOff) { - echo(true); - } - } catch (IOException x) {} - } - }; - } - public Charset charset() { // This method is called in sun.security.util.Password, // cons already exists when this method is called diff --git a/jdk/src/share/classes/java/io/DeleteOnExitHook.java b/jdk/src/share/classes/java/io/DeleteOnExitHook.java index bf4d9e7f20f..1dc5c9d85bc 100644 --- a/jdk/src/share/classes/java/io/DeleteOnExitHook.java +++ b/jdk/src/share/classes/java/io/DeleteOnExitHook.java @@ -34,17 +34,18 @@ import java.io.File; */ class DeleteOnExitHook { - private static DeleteOnExitHook instance = null; + static { + sun.misc.SharedSecrets.getJavaLangAccess() + .registerShutdownHook(2 /* Shutdown hook invocation order */, + new Runnable() { + public void run() { + runHooks(); + } + }); + } private static LinkedHashSet files = new LinkedHashSet(); - static DeleteOnExitHook hook() { - if (instance == null) - instance = new DeleteOnExitHook(); - - return instance; - } - private DeleteOnExitHook() {} static synchronized void add(String file) { @@ -54,7 +55,7 @@ class DeleteOnExitHook { files.add(file); } - void run() { + static void runHooks() { LinkedHashSet theFiles; synchronized (DeleteOnExitHook.class) { diff --git a/jdk/src/share/classes/java/io/File.java b/jdk/src/share/classes/java/io/File.java index 6a0415101fb..6e58efbbd6b 100644 --- a/jdk/src/share/classes/java/io/File.java +++ b/jdk/src/share/classes/java/io/File.java @@ -2147,18 +2147,6 @@ public class File /** use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = 301077366599181567L; - // Set up JavaIODeleteOnExitAccess in SharedSecrets - // Added here as DeleteOnExitHook is package-private and SharedSecrets cannot easily access it. - static { - sun.misc.SharedSecrets.setJavaIODeleteOnExitAccess( - new sun.misc.JavaIODeleteOnExitAccess() { - public void run() { - DeleteOnExitHook.hook().run(); - } - } - ); - } - // -- Integration with java.nio.file -- private volatile transient Path filePath; diff --git a/jdk/src/share/classes/java/lang/ApplicationShutdownHooks.java b/jdk/src/share/classes/java/lang/ApplicationShutdownHooks.java index 8eeb0fef8d0..b3341de15a4 100644 --- a/jdk/src/share/classes/java/lang/ApplicationShutdownHooks.java +++ b/jdk/src/share/classes/java/lang/ApplicationShutdownHooks.java @@ -34,19 +34,19 @@ import java.util.*; * @see java.lang.Runtime#removeShutdownHook */ -class ApplicationShutdownHooks implements Runnable { - private static ApplicationShutdownHooks instance = null; +class ApplicationShutdownHooks { + static { + Shutdown.add(1 /* shutdown hook invocation order */, + new Runnable() { + public void run() { + runHooks(); + } + }); + } /* The set of registered hooks */ private static IdentityHashMap hooks = new IdentityHashMap(); - static synchronized ApplicationShutdownHooks hook() { - if (instance == null) - instance = new ApplicationShutdownHooks(); - - return instance; - } - private ApplicationShutdownHooks() {} /* Add a new shutdown hook. Checks the shutdown state and the hook itself, @@ -82,7 +82,7 @@ class ApplicationShutdownHooks implements Runnable { * to run in. Hooks are run concurrently and this method waits for * them to finish. */ - public void run() { + static void runHooks() { Collection threads; synchronized(ApplicationShutdownHooks.class) { threads = hooks.keySet(); diff --git a/jdk/src/share/classes/java/lang/Shutdown.java b/jdk/src/share/classes/java/lang/Shutdown.java index 18e32d96f8e..b77b45056a7 100644 --- a/jdk/src/share/classes/java/lang/Shutdown.java +++ b/jdk/src/share/classes/java/lang/Shutdown.java @@ -25,8 +25,6 @@ package java.lang; -import java.util.ArrayList; - /** * Package-private utility class containing data structures and logic @@ -47,8 +45,13 @@ class Shutdown { /* Should we run all finalizers upon exit? */ private static boolean runFinalizersOnExit = false; - /* The set of registered, wrapped hooks, or null if there aren't any */ - private static ArrayList hooks = new ArrayList(); + // The system shutdown hooks are registered with a predefined slot. + // The list of shutdown hooks is as follows: + // (0) Console restore hook + // (1) Application hooks + // (2) DeleteOnExit hook + private static final int MAX_SYSTEM_HOOKS = 10; + private static final Runnable[] hooks = new Runnable[MAX_SYSTEM_HOOKS]; /* The preceding static fields are protected by this lock */ private static class Lock { }; @@ -68,33 +71,18 @@ class Shutdown { /* Add a new shutdown hook. Checks the shutdown state and the hook itself, * but does not do any security checks. */ - static void add(Runnable hook) { + static void add(int slot, Runnable hook) { synchronized (lock) { if (state > RUNNING) throw new IllegalStateException("Shutdown in progress"); - hooks.add(hook); + if (hooks[slot] != null) + throw new InternalError("Shutdown hook at slot " + slot + " already registered"); + + hooks[slot] = hook; } } - - /* Remove a previously-registered hook. Like the add method, this method - * does not do any security checks. - */ - static boolean remove(Runnable hook) { - synchronized (lock) { - if (state > RUNNING) - throw new IllegalStateException("Shutdown in progress"); - if (hook == null) throw new NullPointerException(); - if (hooks == null) { - return false; - } else { - return hooks.remove(hook); - } - } - } - - /* Run all registered shutdown hooks */ private static void runHooks() { @@ -103,7 +91,7 @@ class Shutdown { */ for (Runnable hook : hooks) { try { - hook.run(); + if (hook != null) hook.run(); } catch(Throwable t) { if (t instanceof ThreadDeath) { ThreadDeath td = (ThreadDeath)t; diff --git a/jdk/src/share/classes/java/lang/System.java b/jdk/src/share/classes/java/lang/System.java index a81bfa70152..eb62b4087e9 100644 --- a/jdk/src/share/classes/java/lang/System.java +++ b/jdk/src/share/classes/java/lang/System.java @@ -1121,14 +1121,6 @@ public final class System { // Setup Java signal handlers for HUP, TERM, and INT (where available). Terminator.setup(); - // The order in with the hooks are added here is important as it - // determines the order in which they are run. - // (1)Console restore hook needs to be called first. - // (2)Application hooks must be run before calling deleteOnExitHook. - Shutdown.add(sun.misc.SharedSecrets.getJavaIOAccess().consoleRestoreHook()); - Shutdown.add(ApplicationShutdownHooks.hook()); - Shutdown.add(sun.misc.SharedSecrets.getJavaIODeleteOnExitAccess()); - // Initialize any miscellenous operating system settings that need to be // set for the class libraries. Currently this is no-op everywhere except // for Windows where the process-wide error mode is set before the java.io @@ -1174,6 +1166,9 @@ public final class System { public void blockedOn(Thread t, Interruptible b) { t.blockedOn(b); } + public void registerShutdownHook(int slot, Runnable r) { + Shutdown.add(slot, r); + } }); } diff --git a/jdk/src/share/classes/sun/misc/JavaIOAccess.java b/jdk/src/share/classes/sun/misc/JavaIOAccess.java index 2a076a9d84d..f0b50a8ac4e 100644 --- a/jdk/src/share/classes/sun/misc/JavaIOAccess.java +++ b/jdk/src/share/classes/sun/misc/JavaIOAccess.java @@ -29,6 +29,5 @@ import java.nio.charset.Charset; public interface JavaIOAccess { public Console console(); - public Runnable consoleRestoreHook(); public Charset charset(); } diff --git a/jdk/src/share/classes/sun/misc/JavaIODeleteOnExitAccess.java b/jdk/src/share/classes/sun/misc/JavaIODeleteOnExitAccess.java deleted file mode 100644 index 54aef8b428a..00000000000 --- a/jdk/src/share/classes/sun/misc/JavaIODeleteOnExitAccess.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2005 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. Sun designates this - * particular file as subject to the "Classpath" exception as provided - * by Sun in the LICENSE file that accompanied this code. - * - * 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. - */ - -package sun.misc; - -public interface JavaIODeleteOnExitAccess extends Runnable { - public void run(); -} diff --git a/jdk/src/share/classes/sun/misc/JavaLangAccess.java b/jdk/src/share/classes/sun/misc/JavaLangAccess.java index 7c1cc55032f..c288bc8402f 100644 --- a/jdk/src/share/classes/sun/misc/JavaLangAccess.java +++ b/jdk/src/share/classes/sun/misc/JavaLangAccess.java @@ -54,4 +54,7 @@ public interface JavaLangAccess { /** Set thread's blocker field. */ void blockedOn(Thread t, Interruptible b); + + /** register shutdown hook */ + void registerShutdownHook(int slot, Runnable r); } diff --git a/jdk/src/share/classes/sun/misc/SharedSecrets.java b/jdk/src/share/classes/sun/misc/SharedSecrets.java index 938e54c6c50..16b5727c604 100644 --- a/jdk/src/share/classes/sun/misc/SharedSecrets.java +++ b/jdk/src/share/classes/sun/misc/SharedSecrets.java @@ -44,7 +44,6 @@ public class SharedSecrets { private static JavaUtilJarAccess javaUtilJarAccess; private static JavaLangAccess javaLangAccess; private static JavaIOAccess javaIOAccess; - private static JavaIODeleteOnExitAccess javaIODeleteOnExitAccess; private static JavaNetAccess javaNetAccess; private static JavaNioAccess javaNioAccess; private static JavaIOFileDescriptorAccess javaIOFileDescriptorAccess; @@ -103,17 +102,6 @@ public class SharedSecrets { return javaIOAccess; } - public static void setJavaIODeleteOnExitAccess(JavaIODeleteOnExitAccess jida) { - javaIODeleteOnExitAccess = jida; - } - - public static JavaIODeleteOnExitAccess getJavaIODeleteOnExitAccess() { - if (javaIODeleteOnExitAccess == null) { - unsafe.ensureClassInitialized(File.class); - } - return javaIODeleteOnExitAccess; - } - public static void setJavaIOFileDescriptorAccess(JavaIOFileDescriptorAccess jiofda) { javaIOFileDescriptorAccess = jiofda; } From 2f06b83dfcf601211b83b31d99b95b368f266493 Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Thu, 12 Mar 2009 10:32:58 -0700 Subject: [PATCH 23/75] 6813240: Remove dead code in sun.misc.FormattedFloatingDecimal class Remove unused methods from FormattedFloatingDecimal that were originally copied from FloatingDecimal Reviewed-by: darcy --- .../sun/misc/FormattedFloatingDecimal.java | 812 ------------------ 1 file changed, 812 deletions(-) diff --git a/jdk/src/share/classes/sun/misc/FormattedFloatingDecimal.java b/jdk/src/share/classes/sun/misc/FormattedFloatingDecimal.java index a1a658a3e6f..99ba5224950 100644 --- a/jdk/src/share/classes/sun/misc/FormattedFloatingDecimal.java +++ b/jdk/src/share/classes/sun/misc/FormattedFloatingDecimal.java @@ -978,15 +978,6 @@ public class FormattedFloatingDecimal{ return new String(result); } - // This method should only ever be called if this object is constructed - // without Form.DECIMAL_FLOAT because the perThreadBuffer is not large - // enough to handle floating-point numbers of large precision. - public String toJavaFormatString() { - char result[] = (char[])(perThreadBuffer.get()); - int i = getChars(result); - return new String(result, 0, i); - } - // returns the exponent before rounding public int getExponent() { return decExponent - 1; @@ -1157,265 +1148,6 @@ public class FormattedFloatingDecimal{ } }; - // This method should only ever be called if this object is constructed - // without Form.DECIMAL_FLOAT because the perThreadBuffer is not large - // enough to handle floating-point numbers of large precision. - public void appendTo(Appendable buf) { - char result[] = (char[])(perThreadBuffer.get()); - int i = getChars(result); - if (buf instanceof StringBuilder) - ((StringBuilder) buf).append(result, 0, i); - else if (buf instanceof StringBuffer) - ((StringBuffer) buf).append(result, 0, i); - else - assert false; - } - - public static FormattedFloatingDecimal - readJavaFormatString( String in ) throws NumberFormatException { - boolean isNegative = false; - boolean signSeen = false; - int decExp; - char c; - - parseNumber: - try{ - in = in.trim(); // don't fool around with white space. - // throws NullPointerException if null - int l = in.length(); - if ( l == 0 ) throw new NumberFormatException("empty String"); - int i = 0; - switch ( c = in.charAt( i ) ){ - case '-': - isNegative = true; - //FALLTHROUGH - case '+': - i++; - signSeen = true; - } - - // Check for NaN and Infinity strings - c = in.charAt(i); - if(c == 'N' || c == 'I') { // possible NaN or infinity - boolean potentialNaN = false; - char targetChars[] = null; // char arrary of "NaN" or "Infinity" - - if(c == 'N') { - targetChars = notANumber; - potentialNaN = true; - } else { - targetChars = infinity; - } - - // compare Input string to "NaN" or "Infinity" - int j = 0; - while(i < l && j < targetChars.length) { - if(in.charAt(i) == targetChars[j]) { - i++; j++; - } - else // something is amiss, throw exception - break parseNumber; - } - - // For the candidate string to be a NaN or infinity, - // all characters in input string and target char[] - // must be matched ==> j must equal targetChars.length - // and i must equal l - if( (j == targetChars.length) && (i == l) ) { // return NaN or infinity - return (potentialNaN ? new FormattedFloatingDecimal(Double.NaN) // NaN has no sign - : new FormattedFloatingDecimal(isNegative? - Double.NEGATIVE_INFINITY: - Double.POSITIVE_INFINITY)) ; - } - else { // something went wrong, throw exception - break parseNumber; - } - - } else if (c == '0') { // check for hexadecimal floating-point number - if (l > i+1 ) { - char ch = in.charAt(i+1); - if (ch == 'x' || ch == 'X' ) // possible hex string - return parseHexString(in); - } - } // look for and process decimal floating-point string - - char[] digits = new char[ l ]; - int nDigits= 0; - boolean decSeen = false; - int decPt = 0; - int nLeadZero = 0; - int nTrailZero= 0; - digitLoop: - while ( i < l ){ - switch ( c = in.charAt( i ) ){ - case '0': - if ( nDigits > 0 ){ - nTrailZero += 1; - } else { - nLeadZero += 1; - } - break; // out of switch. - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - while ( nTrailZero > 0 ){ - digits[nDigits++] = '0'; - nTrailZero -= 1; - } - digits[nDigits++] = c; - break; // out of switch. - case '.': - if ( decSeen ){ - // already saw one ., this is the 2nd. - throw new NumberFormatException("multiple points"); - } - decPt = i; - if ( signSeen ){ - decPt -= 1; - } - decSeen = true; - break; // out of switch. - default: - break digitLoop; - } - i++; - } - /* - * At this point, we've scanned all the digits and decimal - * point we're going to see. Trim off leading and trailing - * zeros, which will just confuse us later, and adjust - * our initial decimal exponent accordingly. - * To review: - * we have seen i total characters. - * nLeadZero of them were zeros before any other digits. - * nTrailZero of them were zeros after any other digits. - * if ( decSeen ), then a . was seen after decPt characters - * ( including leading zeros which have been discarded ) - * nDigits characters were neither lead nor trailing - * zeros, nor point - */ - /* - * special hack: if we saw no non-zero digits, then the - * answer is zero! - * Unfortunately, we feel honor-bound to keep parsing! - */ - if ( nDigits == 0 ){ - digits = zero; - nDigits = 1; - if ( nLeadZero == 0 ){ - // we saw NO DIGITS AT ALL, - // not even a crummy 0! - // this is not allowed. - break parseNumber; // go throw exception - } - - } - - /* Our initial exponent is decPt, adjusted by the number of - * discarded zeros. Or, if there was no decPt, - * then its just nDigits adjusted by discarded trailing zeros. - */ - if ( decSeen ){ - decExp = decPt - nLeadZero; - } else { - decExp = nDigits+nTrailZero; - } - - /* - * Look for 'e' or 'E' and an optionally signed integer. - */ - if ( (i < l) && (((c = in.charAt(i) )=='e') || (c == 'E') ) ){ - int expSign = 1; - int expVal = 0; - int reallyBig = Integer.MAX_VALUE / 10; - boolean expOverflow = false; - switch( in.charAt(++i) ){ - case '-': - expSign = -1; - //FALLTHROUGH - case '+': - i++; - } - int expAt = i; - expLoop: - while ( i < l ){ - if ( expVal >= reallyBig ){ - // the next character will cause integer - // overflow. - expOverflow = true; - } - switch ( c = in.charAt(i++) ){ - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - expVal = expVal*10 + ( (int)c - (int)'0' ); - continue; - default: - i--; // back up. - break expLoop; // stop parsing exponent. - } - } - int expLimit = bigDecimalExponent+nDigits+nTrailZero; - if ( expOverflow || ( expVal > expLimit ) ){ - // - // The intent here is to end up with - // infinity or zero, as appropriate. - // The reason for yielding such a small decExponent, - // rather than something intuitive such as - // expSign*Integer.MAX_VALUE, is that this value - // is subject to further manipulation in - // doubleValue() and floatValue(), and I don't want - // it to be able to cause overflow there! - // (The only way we can get into trouble here is for - // really outrageous nDigits+nTrailZero, such as 2 billion. ) - // - decExp = expSign*expLimit; - } else { - // this should not overflow, since we tested - // for expVal > (MAX+N), where N >= abs(decExp) - decExp = decExp + expSign*expVal; - } - - // if we saw something not a digit ( or end of string ) - // after the [Ee][+-], without seeing any digits at all - // this is certainly an error. If we saw some digits, - // but then some trailing garbage, that might be ok. - // so we just fall through in that case. - // HUMBUG - if ( i == expAt ) - break parseNumber; // certainly bad - } - /* - * We parsed everything we could. - * If there are leftovers, then this is not good input! - */ - if ( i < l && - ((i != l - 1) || - (in.charAt(i) != 'f' && - in.charAt(i) != 'F' && - in.charAt(i) != 'd' && - in.charAt(i) != 'D'))) { - break parseNumber; // go throw exception - } - - return new FormattedFloatingDecimal( isNegative, decExp, digits, nDigits, false, Integer.MAX_VALUE, Form.COMPATIBLE ); - } catch ( StringIndexOutOfBoundsException e ){ } - throw new NumberFormatException("For input string: \"" + in + "\""); - } - /* * Take a FormattedFloatingDecimal, which we presumably just scanned in, * and find out what its value is, as a double. @@ -2035,548 +1767,4 @@ public class FormattedFloatingDecimal{ private static final char infinity[] = { 'I', 'n', 'f', 'i', 'n', 'i', 't', 'y' }; private static final char notANumber[] = { 'N', 'a', 'N' }; private static final char zero[] = { '0', '0', '0', '0', '0', '0', '0', '0' }; - - - /* - * Grammar is compatible with hexadecimal floating-point constants - * described in section 6.4.4.2 of the C99 specification. - */ - private static Pattern hexFloatPattern = Pattern.compile( - //1 234 56 7 8 9 - "([-+])?0[xX](((\\p{XDigit}+)\\.?)|((\\p{XDigit}*)\\.(\\p{XDigit}+)))[pP]([-+])?(\\p{Digit}+)[fFdD]?" - ); - - /* - * Convert string s to a suitable floating decimal; uses the - * double constructor and set the roundDir variable appropriately - * in case the value is later converted to a float. - */ - static FormattedFloatingDecimal parseHexString(String s) { - // Verify string is a member of the hexadecimal floating-point - // string language. - Matcher m = hexFloatPattern.matcher(s); - boolean validInput = m.matches(); - - if (!validInput) { - // Input does not match pattern - throw new NumberFormatException("For input string: \"" + s + "\""); - } else { // validInput - /* - * We must isolate the sign, significand, and exponent - * fields. The sign value is straightforward. Since - * floating-point numbers are stored with a normalized - * representation, the significand and exponent are - * interrelated. - * - * After extracting the sign, we normalized the - * significand as a hexadecimal value, calculating an - * exponent adjust for any shifts made during - * normalization. If the significand is zero, the - * exponent doesn't need to be examined since the output - * will be zero. - * - * Next the exponent in the input string is extracted. - * Afterwards, the significand is normalized as a *binary* - * value and the input value's normalized exponent can be - * computed. The significand bits are copied into a - * double significand; if the string has more logical bits - * than can fit in a double, the extra bits affect the - * round and sticky bits which are used to round the final - * value. - */ - - // Extract significand sign - String group1 = m.group(1); - double sign = (( group1 == null ) || group1.equals("+"))? 1.0 : -1.0; - - - // Extract Significand magnitude - /* - * Based on the form of the significand, calculate how the - * binary exponent needs to be adjusted to create a - * normalized *hexadecimal* floating-point number; that - * is, a number where there is one nonzero hex digit to - * the left of the (hexa)decimal point. Since we are - * adjusting a binary, not hexadecimal exponent, the - * exponent is adjusted by a multiple of 4. - * - * There are a number of significand scenarios to consider; - * letters are used in indicate nonzero digits: - * - * 1. 000xxxx => x.xxx normalized - * increase exponent by (number of x's - 1)*4 - * - * 2. 000xxx.yyyy => x.xxyyyy normalized - * increase exponent by (number of x's - 1)*4 - * - * 3. .000yyy => y.yy normalized - * decrease exponent by (number of zeros + 1)*4 - * - * 4. 000.00000yyy => y.yy normalized - * decrease exponent by (number of zeros to right of point + 1)*4 - * - * If the significand is exactly zero, return a properly - * signed zero. - */ - - String significandString =null; - int signifLength = 0; - int exponentAdjust = 0; - { - int leftDigits = 0; // number of meaningful digits to - // left of "decimal" point - // (leading zeros stripped) - int rightDigits = 0; // number of digits to right of - // "decimal" point; leading zeros - // must always be accounted for - /* - * The significand is made up of either - * - * 1. group 4 entirely (integer portion only) - * - * OR - * - * 2. the fractional portion from group 7 plus any - * (optional) integer portions from group 6. - */ - String group4; - if( (group4 = m.group(4)) != null) { // Integer-only significand - // Leading zeros never matter on the integer portion - significandString = stripLeadingZeros(group4); - leftDigits = significandString.length(); - } - else { - // Group 6 is the optional integer; leading zeros - // never matter on the integer portion - String group6 = stripLeadingZeros(m.group(6)); - leftDigits = group6.length(); - - // fraction - String group7 = m.group(7); - rightDigits = group7.length(); - - // Turn "integer.fraction" into "integer"+"fraction" - significandString = - ((group6 == null)?"":group6) + // is the null - // check necessary? - group7; - } - - significandString = stripLeadingZeros(significandString); - signifLength = significandString.length(); - - /* - * Adjust exponent as described above - */ - if (leftDigits >= 1) { // Cases 1 and 2 - exponentAdjust = 4*(leftDigits - 1); - } else { // Cases 3 and 4 - exponentAdjust = -4*( rightDigits - signifLength + 1); - } - - // If the significand is zero, the exponent doesn't - // matter; return a properly signed zero. - - if (signifLength == 0) { // Only zeros in input - return new FormattedFloatingDecimal(sign * 0.0); - } - } - - // Extract Exponent - /* - * Use an int to read in the exponent value; this should - * provide more than sufficient range for non-contrived - * inputs. If reading the exponent in as an int does - * overflow, examine the sign of the exponent and - * significand to determine what to do. - */ - String group8 = m.group(8); - boolean positiveExponent = ( group8 == null ) || group8.equals("+"); - long unsignedRawExponent; - try { - unsignedRawExponent = Integer.parseInt(m.group(9)); - } - catch (NumberFormatException e) { - // At this point, we know the exponent is - // syntactically well-formed as a sequence of - // digits. Therefore, if an NumberFormatException - // is thrown, it must be due to overflowing int's - // range. Also, at this point, we have already - // checked for a zero significand. Thus the signs - // of the exponent and significand determine the - // final result: - // - // significand - // + - - // exponent + +infinity -infinity - // - +0.0 -0.0 - return new FormattedFloatingDecimal(sign * (positiveExponent ? - Double.POSITIVE_INFINITY : 0.0)); - } - - long rawExponent = - (positiveExponent ? 1L : -1L) * // exponent sign - unsignedRawExponent; // exponent magnitude - - // Calculate partially adjusted exponent - long exponent = rawExponent + exponentAdjust ; - - // Starting copying non-zero bits into proper position in - // a long; copy explicit bit too; this will be masked - // later for normal values. - - boolean round = false; - boolean sticky = false; - int bitsCopied=0; - int nextShift=0; - long significand=0L; - // First iteration is different, since we only copy - // from the leading significand bit; one more exponent - // adjust will be needed... - - // IMPORTANT: make leadingDigit a long to avoid - // surprising shift semantics! - long leadingDigit = getHexDigit(significandString, 0); - - /* - * Left shift the leading digit (53 - (bit position of - * leading 1 in digit)); this sets the top bit of the - * significand to 1. The nextShift value is adjusted - * to take into account the number of bit positions of - * the leadingDigit actually used. Finally, the - * exponent is adjusted to normalize the significand - * as a binary value, not just a hex value. - */ - if (leadingDigit == 1) { - significand |= leadingDigit << 52; - nextShift = 52 - 4; - /* exponent += 0 */ } - else if (leadingDigit <= 3) { // [2, 3] - significand |= leadingDigit << 51; - nextShift = 52 - 5; - exponent += 1; - } - else if (leadingDigit <= 7) { // [4, 7] - significand |= leadingDigit << 50; - nextShift = 52 - 6; - exponent += 2; - } - else if (leadingDigit <= 15) { // [8, f] - significand |= leadingDigit << 49; - nextShift = 52 - 7; - exponent += 3; - } else { - throw new AssertionError("Result from digit converstion too large!"); - } - // The preceding if-else could be replaced by a single - // code block based on the high-order bit set in - // leadingDigit. Given leadingOnePosition, - - // significand |= leadingDigit << (SIGNIFICAND_WIDTH - leadingOnePosition); - // nextShift = 52 - (3 + leadingOnePosition); - // exponent += (leadingOnePosition-1); - - - /* - * Now the exponent variable is equal to the normalized - * binary exponent. Code below will make representation - * adjustments if the exponent is incremented after - * rounding (includes overflows to infinity) or if the - * result is subnormal. - */ - - // Copy digit into significand until the significand can't - // hold another full hex digit or there are no more input - // hex digits. - int i = 0; - for(i = 1; - i < signifLength && nextShift >= 0; - i++) { - long currentDigit = getHexDigit(significandString, i); - significand |= (currentDigit << nextShift); - nextShift-=4; - } - - // After the above loop, the bulk of the string is copied. - // Now, we must copy any partial hex digits into the - // significand AND compute the round bit and start computing - // sticky bit. - - if ( i < signifLength ) { // at least one hex input digit exists - long currentDigit = getHexDigit(significandString, i); - - // from nextShift, figure out how many bits need - // to be copied, if any - switch(nextShift) { // must be negative - case -1: - // three bits need to be copied in; can - // set round bit - significand |= ((currentDigit & 0xEL) >> 1); - round = (currentDigit & 0x1L) != 0L; - break; - - case -2: - // two bits need to be copied in; can - // set round and start sticky - significand |= ((currentDigit & 0xCL) >> 2); - round = (currentDigit &0x2L) != 0L; - sticky = (currentDigit & 0x1L) != 0; - break; - - case -3: - // one bit needs to be copied in - significand |= ((currentDigit & 0x8L)>>3); - // Now set round and start sticky, if possible - round = (currentDigit &0x4L) != 0L; - sticky = (currentDigit & 0x3L) != 0; - break; - - case -4: - // all bits copied into significand; set - // round and start sticky - round = ((currentDigit & 0x8L) != 0); // is top bit set? - // nonzeros in three low order bits? - sticky = (currentDigit & 0x7L) != 0; - break; - - default: - throw new AssertionError("Unexpected shift distance remainder."); - // break; - } - - // Round is set; sticky might be set. - - // For the sticky bit, it suffices to check the - // current digit and test for any nonzero digits in - // the remaining unprocessed input. - i++; - while(i < signifLength && !sticky) { - currentDigit = getHexDigit(significandString,i); - sticky = sticky || (currentDigit != 0); - i++; - } - - } - // else all of string was seen, round and sticky are - // correct as false. - - - // Check for overflow and update exponent accordingly. - - if (exponent > DoubleConsts.MAX_EXPONENT) { // Infinite result - // overflow to properly signed infinity - return new FormattedFloatingDecimal(sign * Double.POSITIVE_INFINITY); - } else { // Finite return value - if (exponent <= DoubleConsts.MAX_EXPONENT && // (Usually) normal result - exponent >= DoubleConsts.MIN_EXPONENT) { - - // The result returned in this block cannot be a - // zero or subnormal; however after the - // significand is adjusted from rounding, we could - // still overflow in infinity. - - // AND exponent bits into significand; if the - // significand is incremented and overflows from - // rounding, this combination will update the - // exponent correctly, even in the case of - // Double.MAX_VALUE overflowing to infinity. - - significand = (( ((long)exponent + - (long)DoubleConsts.EXP_BIAS) << - (DoubleConsts.SIGNIFICAND_WIDTH-1)) - & DoubleConsts.EXP_BIT_MASK) | - (DoubleConsts.SIGNIF_BIT_MASK & significand); - - } else { // Subnormal or zero - // (exponent < DoubleConsts.MIN_EXPONENT) - - if (exponent < (DoubleConsts.MIN_SUB_EXPONENT -1 )) { - // No way to round back to nonzero value - // regardless of significand if the exponent is - // less than -1075. - return new FormattedFloatingDecimal(sign * 0.0); - } else { // -1075 <= exponent <= MIN_EXPONENT -1 = -1023 - /* - * Find bit position to round to; recompute - * round and sticky bits, and shift - * significand right appropriately. - */ - - sticky = sticky || round; - round = false; - - // Number of bits of significand to preserve is - // exponent - abs_min_exp +1 - // check: - // -1075 +1074 + 1 = 0 - // -1023 +1074 + 1 = 52 - - int bitsDiscarded = 53 - - ((int)exponent - DoubleConsts.MIN_SUB_EXPONENT + 1); - assert bitsDiscarded >= 1 && bitsDiscarded <= 53; - - // What to do here: - // First, isolate the new round bit - round = (significand & (1L << (bitsDiscarded -1))) != 0L; - if (bitsDiscarded > 1) { - // create mask to update sticky bits; low - // order bitsDiscarded bits should be 1 - long mask = ~((~0L) << (bitsDiscarded -1)); - sticky = sticky || ((significand & mask) != 0L ) ; - } - - // Now, discard the bits - significand = significand >> bitsDiscarded; - - significand = (( ((long)(DoubleConsts.MIN_EXPONENT -1) + // subnorm exp. - (long)DoubleConsts.EXP_BIAS) << - (DoubleConsts.SIGNIFICAND_WIDTH-1)) - & DoubleConsts.EXP_BIT_MASK) | - (DoubleConsts.SIGNIF_BIT_MASK & significand); - } - } - - // The significand variable now contains the currently - // appropriate exponent bits too. - - /* - * Determine if significand should be incremented; - * making this determination depends on the least - * significant bit and the round and sticky bits. - * - * Round to nearest even rounding table, adapted from - * table 4.7 in "Computer Arithmetic" by IsraelKoren. - * The digit to the left of the "decimal" point is the - * least significant bit, the digits to the right of - * the point are the round and sticky bits - * - * Number Round(x) - * x0.00 x0. - * x0.01 x0. - * x0.10 x0. - * x0.11 x1. = x0. +1 - * x1.00 x1. - * x1.01 x1. - * x1.10 x1. + 1 - * x1.11 x1. + 1 - */ - boolean incremented = false; - boolean leastZero = ((significand & 1L) == 0L); - if( ( leastZero && round && sticky ) || - ((!leastZero) && round )) { - incremented = true; - significand++; - } - - FormattedFloatingDecimal fd = new FormattedFloatingDecimal(FpUtils.rawCopySign( - Double.longBitsToDouble(significand), - sign)); - - /* - * Set roundingDir variable field of fd properly so - * that the input string can be properly rounded to a - * float value. There are two cases to consider: - * - * 1. rounding to double discards sticky bit - * information that would change the result of a float - * rounding (near halfway case between two floats) - * - * 2. rounding to double rounds up when rounding up - * would not occur when rounding to float. - * - * For former case only needs to be considered when - * the bits rounded away when casting to float are all - * zero; otherwise, float round bit is properly set - * and sticky will already be true. - * - * The lower exponent bound for the code below is the - * minimum (normalized) subnormal exponent - 1 since a - * value with that exponent can round up to the - * minimum subnormal value and the sticky bit - * information must be preserved (i.e. case 1). - */ - if ((exponent >= FloatConsts.MIN_SUB_EXPONENT-1) && - (exponent <= FloatConsts.MAX_EXPONENT ) ){ - // Outside above exponent range, the float value - // will be zero or infinity. - - /* - * If the low-order 28 bits of a rounded double - * significand are 0, the double could be a - * half-way case for a rounding to float. If the - * double value is a half-way case, the double - * significand may have to be modified to round - * the the right float value (see the stickyRound - * method). If the rounding to double has lost - * what would be float sticky bit information, the - * double significand must be incremented. If the - * double value's significand was itself - * incremented, the float value may end up too - * large so the increment should be undone. - */ - if ((significand & 0xfffffffL) == 0x0L) { - // For negative values, the sign of the - // roundDir is the same as for positive values - // since adding 1 increasing the significand's - // magnitude and subtracting 1 decreases the - // significand's magnitude. If neither round - // nor sticky is true, the double value is - // exact and no adjustment is required for a - // proper float rounding. - if( round || sticky) { - if (leastZero) { // prerounding lsb is 0 - // If round and sticky were both true, - // and the least significant - // significand bit were 0, the rounded - // significand would not have its - // low-order bits be zero. Therefore, - // we only need to adjust the - // significand if round XOR sticky is - // true. - if (round ^ sticky) { - fd.roundDir = 1; - } - } - else { // prerounding lsb is 1 - // If the prerounding lsb is 1 and the - // resulting significand has its - // low-order bits zero, the significand - // was incremented. Here, we undo the - // increment, which will ensure the - // right guard and sticky bits for the - // float rounding. - if (round) - fd.roundDir = -1; - } - } - } - } - - fd.fromHex = true; - return fd; - } - } - } - - /** - * Return s with any leading zeros removed. - */ - static String stripLeadingZeros(String s) { - return s.replaceFirst("^0+", ""); - } - - /** - * Extract a hexadecimal digit from position position - * of string s. - */ - static int getHexDigit(String s, int position) { - int value = Character.digit(s.charAt(position), 16); - if (value <= -1 || value >= 16) { - throw new AssertionError("Unxpected failure of digit converstion of " + - s.charAt(position)); - } - return value; - } - - } From 5f9073cac047936d83062743a9c1789305b8f827 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Thu, 12 Mar 2009 12:01:49 -0700 Subject: [PATCH 24/75] 6727719: Performance of TextLayout.getBounds() Reviewed-by: jgodinez, dougfelt --- .../share/classes/sun/font/FileFontStrike.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/jdk/src/share/classes/sun/font/FileFontStrike.java b/jdk/src/share/classes/sun/font/FileFontStrike.java index dab135e96d2..4628016a216 100644 --- a/jdk/src/share/classes/sun/font/FileFontStrike.java +++ b/jdk/src/share/classes/sun/font/FileFontStrike.java @@ -842,8 +842,22 @@ public class FileFontStrike extends PhysicalStrike { return fileFont.getGlyphOutlineBounds(pScalerContext, glyphCode); } + private ConcurrentHashMap outlineMap; + GeneralPath getGlyphOutline(int glyphCode, float x, float y) { - return fileFont.getGlyphOutline(pScalerContext, glyphCode, x, y); + if (outlineMap == null) { + outlineMap = new ConcurrentHashMap(); + } + GeneralPath gp = (GeneralPath)outlineMap.get(glyphCode); + if (gp == null) { + gp = fileFont.getGlyphOutline(pScalerContext, glyphCode, 0, 0); + outlineMap.put(glyphCode, gp); + } + gp = (GeneralPath)gp.clone(); // mutable! + if (x != 0f || y != 0f) { + gp.transform(AffineTransform.getTranslateInstance(x, y)); + } + return gp; } GeneralPath getGlyphVectorOutline(int[] glyphs, float x, float y) { From 78ae650f8f866b0e9341c928fff17bed67e5ad58 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Fri, 13 Mar 2009 09:20:56 +0800 Subject: [PATCH 25/75] 6815182: GSSAPI/SPNEGO does not work with server using MIT Kerberos library Reviewed-by: valeriep --- .../security/jgss/spnego/NegTokenInit.java | 10 +- .../security/jgss/spnego/SpNegoContext.java | 35 ++----- .../security/krb5/auto/SpnegoReqFlags.java | 92 +++++++++++++++++++ 3 files changed, 107 insertions(+), 30 deletions(-) create mode 100644 jdk/test/sun/security/krb5/auto/SpnegoReqFlags.java diff --git a/jdk/src/share/classes/sun/security/jgss/spnego/NegTokenInit.java b/jdk/src/share/classes/sun/security/jgss/spnego/NegTokenInit.java index 6003cdfaeab..9bb77fd7a1d 100644 --- a/jdk/src/share/classes/sun/security/jgss/spnego/NegTokenInit.java +++ b/jdk/src/share/classes/sun/security/jgss/spnego/NegTokenInit.java @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-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 @@ -66,11 +66,11 @@ public class NegTokenInit extends SpNegoToken { private byte[] mechTypes = null; private Oid[] mechTypeList = null; - private byte[] reqFlags = null; + private BitArray reqFlags = null; private byte[] mechToken = null; private byte[] mechListMIC = null; - NegTokenInit(byte[] mechTypes, byte[] flags, + NegTokenInit(byte[] mechTypes, BitArray flags, byte[] token, byte[] mechListMIC) { super(NEG_TOKEN_INIT_ID); @@ -101,7 +101,7 @@ public class NegTokenInit extends SpNegoToken { // write context flags with CONTEXT 01 if (reqFlags != null) { DerOutputStream flags = new DerOutputStream(); - flags.putBitString(reqFlags); + flags.putUnalignedBitString(reqFlags); initToken.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x01), flags); } @@ -237,7 +237,7 @@ public class NegTokenInit extends SpNegoToken { return mechTypeList; } - byte[] getReqFlags() { + BitArray getReqFlags() { return reqFlags; } diff --git a/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java b/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java index 7185b0e08a7..a84e8a26001 100644 --- a/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java +++ b/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-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 @@ -53,13 +53,6 @@ public class SpNegoContext implements GSSContextSpi { private int state = STATE_NEW; - private static final int CHECKSUM_DELEG_FLAG = 1; - private static final int CHECKSUM_MUTUAL_FLAG = 2; - private static final int CHECKSUM_REPLAY_FLAG = 4; - private static final int CHECKSUM_SEQUENCE_FLAG = 8; - private static final int CHECKSUM_CONF_FLAG = 16; - private static final int CHECKSUM_INTEG_FLAG = 32; - /* * Optional features that the application can set and their default * values. @@ -697,25 +690,17 @@ public class SpNegoContext implements GSSContextSpi { /** * get the context flags */ - private byte[] getContextFlags() { - int flags = 0; + private BitArray getContextFlags() { + BitArray out = new BitArray(7); - if (getCredDelegState()) - flags |= CHECKSUM_DELEG_FLAG; - if (getMutualAuthState()) - flags |= CHECKSUM_MUTUAL_FLAG; - if (getReplayDetState()) - flags |= CHECKSUM_REPLAY_FLAG; - if (getSequenceDetState()) - flags |= CHECKSUM_SEQUENCE_FLAG; - if (getIntegState()) - flags |= CHECKSUM_INTEG_FLAG; - if (getConfState()) - flags |= CHECKSUM_CONF_FLAG; + if (getCredDelegState()) out.set(0, true); + if (getMutualAuthState()) out.set(1, true); + if (getReplayDetState()) out.set(2, true); + if (getSequenceDetState()) out.set(3, true); + if (getConfState()) out.set(5, true); + if (getIntegState()) out.set(6, true); - byte[] temp = new byte[1]; - temp[0] = (byte)(flags & 0xff); - return temp; + return out; } private void setContextFlags() { diff --git a/jdk/test/sun/security/krb5/auto/SpnegoReqFlags.java b/jdk/test/sun/security/krb5/auto/SpnegoReqFlags.java new file mode 100644 index 00000000000..a94a2b5d1ac --- /dev/null +++ b/jdk/test/sun/security/krb5/auto/SpnegoReqFlags.java @@ -0,0 +1,92 @@ +/* + * 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 6815182 + * @summary GSSAPI/SPNEGO does not work with server using MIT Kerberos library + */ + +import sun.security.jgss.GSSUtil; +import sun.security.util.BitArray; +import sun.security.util.DerInputStream; +import sun.security.util.DerValue; + +public class SpnegoReqFlags { + + public static void main(String[] args) + throws Exception { + + // Create and start the KDC + new OneKDC(null).writeJAASConf(); + new SpnegoReqFlags().go(); + } + + void go() throws Exception { + Context c = Context.fromJAAS("client"); + c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_SPNEGO_MECH_OID); + + byte[] token = c.doAs(new Action() { + @Override + public byte[] run(Context me, byte[] input) throws Exception { + me.x().requestCredDeleg(true); + me.x().requestReplayDet(false); + me.x().requestSequenceDet(false); + return me.x().initSecContext(new byte[0], 0, 0); + } + }, null); + + DerValue d = new DerValue(token); // GSSToken + DerInputStream ins = d.data; // OID + mech token + d.data.getDerValue(); // skip OID + d = d.data.getDerValue(); // NegTokenInit + d = d.data.getDerValue(); // The SEQUENCE inside + + boolean found = false; + + // Go through all fields inside NegTokenInit. The reqFlags field + // is optional. It's even not recommended in RFC 4178. + while (d.data.available() > 0) { + DerValue d2 = d.data.getDerValue(); + if (d2.isContextSpecific((byte)1)) { + found = true; + System.out.println("regFlags field located."); + BitArray ba = d2.data.getUnalignedBitString(); + if (ba.length() != 7) { + throw new Exception("reqFlags should contain 7 bits"); + } + if (!ba.get(0)) { + throw new Exception("delegFlag should be true"); + } + if (ba.get(2) || ba.get(3)) { + throw new Exception("replay/sequenceFlag should be false"); + } + } + } + + if (!found) { + System.out.println("Warning: regFlags field not found, too new?"); + } + c.dispose(); + } +} From d6f2afc28f0e2d6681d0b3d5d412bade9c4a1502 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Fri, 13 Mar 2009 09:21:13 +0800 Subject: [PATCH 26/75] 6550221: jaas, jgss and smartcardio javadoc files do not contain Copyrights Reviewed-by: ohair --- jdk/make/docs/Makefile | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/jdk/make/docs/Makefile b/jdk/make/docs/Makefile index 492fa059160..301acde0826 100644 --- a/jdk/make/docs/Makefile +++ b/jdk/make/docs/Makefile @@ -1,5 +1,5 @@ # -# Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 1997-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 @@ -204,6 +204,9 @@ JDI_DOCTITLE = "Java$(TRADEMARK) Debug Interface" JDI_HEADER = "Java Debug Interface" # JDI_PKGS is located in NON_CORE_PKGS.gmk +# Variables used by security components +SECURITYAPI_JAVADOCBOTTOM = 'Report a bug or request a feature.
Copyright $(THIS_YEAR) Sun Microsystems, Inc. All Rights Reserved. Use is subject to license terms.
' + # # Variables used by JAAS target # @@ -221,6 +224,7 @@ JAAS_JAVADOCFLAGS = $(COMMON_JAVADOCFLAGS) \ -windowtitle $(JAAS_WINDOWTITLE) \ -doctitle $(JAAS_DOCTITLE) \ -header $(JAAS_JAVADOCHEADER) \ + -bottom $(SECURITYAPI_JAVADOCBOTTOM) \ -linkoffline ../../../../../api $(DOCSDIR)/api/ \ -overview $(TOPDIR)/src/share/classes/com/sun/security/auth/jaas-overview.html JAAS_WINDOWTITLE = "Java Authentication and Authorization Service " @@ -243,6 +247,7 @@ JGSS_JAVADOCFLAGS = $(COMMON_JAVADOCFLAGS) \ -windowtitle $(JGSS_WINDOWTITLE) \ -doctitle $(JGSS_DOCTITLE) \ -header $(JGSS_JAVADOCHEADER) \ + -bottom $(SECURITYAPI_JAVADOCBOTTOM) \ -linkoffline ../../../../../api $(DOCSDIR)/api/ \ -overview $(JGSS_SOURCEPATH)/com/sun/security/jgss/jgss-overview.html @@ -266,6 +271,7 @@ SMARTCARDIO_JAVADOCFLAGS = $(COMMON_JAVADOCFLAGS) \ -windowtitle $(SMARTCARDIO_WINDOWTITLE) \ -doctitle $(SMARTCARDIO_DOCTITLE) \ -header $(SMARTCARDIO_JAVADOCHEADER) \ + -bottom $(SECURITYAPI_JAVADOCBOTTOM) \ -linkoffline ../../../../../api $(DOCSDIR)/api/ SMARTCARDIO_WINDOWTITLE = "Java Smart Card I/O" From 95ef28ff0d979d4b1664e9ec8a6cc136ce5a1839 Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan Date: Fri, 13 Mar 2009 12:59:25 +0800 Subject: [PATCH 27/75] 6798714: OCSPResponse class has to check the validity of signing certificate for OCSP response Checking validity and ocsp-nocheck extension. Reviewed-by: mullan, vinnie --- .../provider/certpath/OCSPResponse.java | 55 +++++++- .../security/x509/OCSPNoCheckExtension.java | 132 ++++++++++++++++++ .../classes/sun/security/x509/OIDMap.java | 4 + .../sun/security/x509/PKIXExtensions.java | 11 +- 4 files changed, 195 insertions(+), 7 deletions(-) create mode 100644 jdk/src/share/classes/sun/security/x509/OCSPNoCheckExtension.java diff --git a/jdk/src/share/classes/sun/security/provider/certpath/OCSPResponse.java b/jdk/src/share/classes/sun/security/provider/certpath/OCSPResponse.java index 20bac34f2cc..62cd4288ed0 100644 --- a/jdk/src/share/classes/sun/security/provider/certpath/OCSPResponse.java +++ b/jdk/src/share/classes/sun/security/provider/certpath/OCSPResponse.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-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 @@ -28,8 +28,6 @@ package sun.security.provider.certpath; import java.io.*; import java.math.BigInteger; import java.security.*; -import java.security.cert.Certificate; -import java.security.cert.CertificateFactory; import java.security.cert.CertPathValidatorException; import java.security.cert.CRLReason; import java.security.cert.X509Certificate; @@ -335,7 +333,7 @@ class OCSPResponse { // Check whether the cert returned by the responder is trusted if (x509Certs != null && x509Certs[0] != null) { - X509Certificate cert = x509Certs[0]; + X509CertImpl cert = x509Certs[0]; // First check if the cert matches the responder cert which // was set locally. @@ -344,8 +342,8 @@ class OCSPResponse { // Next check if the cert was issued by the responder cert // which was set locally. - } else if (cert.getIssuerDN().equals( - responderCert.getSubjectDN())) { + } else if (cert.getIssuerX500Principal().equals( + responderCert.getSubjectX500Principal())) { // Check for the OCSPSigning key purpose List keyPurposes = cert.getExtendedKeyUsage(); @@ -360,6 +358,43 @@ class OCSPResponse { "OCSP responses"); } + // check the validity + try { + Date dateCheckedAgainst = params.getDate(); + if (dateCheckedAgainst == null) { + cert.checkValidity(); + } else { + cert.checkValidity(dateCheckedAgainst); + } + } catch (GeneralSecurityException e) { + if (DEBUG != null) { + DEBUG.println("Responder's certificate is not " + + "within the validity period."); + } + throw new CertPathValidatorException( + "Responder's certificate not within the " + + "validity period"); + } + + // check for revocation + // + // A CA may specify that an OCSP client can trust a + // responder for the lifetime of the responder's + // certificate. The CA does so by including the + // extension id-pkix-ocsp-nocheck. + // + Extension noCheck = + cert.getExtension(PKIXExtensions.OCSPNoCheck_Id); + if (noCheck != null) { + if (DEBUG != null) { + DEBUG.println("Responder's certificate includes " + + "the extension id-pkix-ocsp-nocheck."); + } + } else { + // we should do the revocating checking of the + // authorized responder in a future update. + } + // verify the signature try { cert.verify(responderCert.getPublicKey()); @@ -369,6 +404,14 @@ class OCSPResponse { } catch (GeneralSecurityException e) { responderCert = null; } + } else { + if (DEBUG != null) { + DEBUG.println("Responder's certificate is not " + + "authorized to sign OCSP responses."); + } + throw new CertPathValidatorException( + "Responder's certificate not authorized to sign " + + "OCSP responses"); } } diff --git a/jdk/src/share/classes/sun/security/x509/OCSPNoCheckExtension.java b/jdk/src/share/classes/sun/security/x509/OCSPNoCheckExtension.java new file mode 100644 index 00000000000..b721439d5c9 --- /dev/null +++ b/jdk/src/share/classes/sun/security/x509/OCSPNoCheckExtension.java @@ -0,0 +1,132 @@ +/* + * 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.security.x509; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Enumeration; + +import sun.security.util.*; + +/** + * Represent the OCSP NoCheck Extension from RFC2560. + *

+ * A CA may specify that an OCSP client can trust a responder for the + * lifetime of the responder's certificate. The CA does so by including + * the extension id-pkix-ocsp-nocheck. This SHOULD be a non-critical + * extension. The value of the extension should be NULL. CAs issuing + * such a certificate should realized that a compromise of the + * responder's key, is as serious as the compromise of a CA key used to + * sign CRLs, at least for the validity period of this certificate. CA's + * may choose to issue this type of certificate with a very short + * lifetime and renew it frequently. + *

+ * id-pkix-ocsp-nocheck OBJECT IDENTIFIER ::= { id-pkix-ocsp 5 }
+ * 
+ * + * @author Xuelei Fan + * @see Extension + * @see CertAttrSet + */ +public class OCSPNoCheckExtension extends Extension + implements CertAttrSet { + + /** + * Identifier for this attribute, to be used with the + * get, set, delete methods of Certificate, x509 type. + */ + public static final String IDENT = + "x509.info.extensions.OCSPNoCheck"; + /** + * Attribute names. + */ + public static final String NAME = "OCSPNoCheck"; + + /** + * Create a OCSPNoCheckExtension + */ + public OCSPNoCheckExtension() throws IOException { + this.extensionId = PKIXExtensions.OCSPNoCheck_Id; + this.critical = false; + this.extensionValue = new byte[0]; + } + + /** + * Create the extension from the passed DER encoded value. + * + * @param critical true if the extension is to be treated as critical. + * @param value an array of DER encoded bytes of the actual value. + * @exception IOException on error. + */ + public OCSPNoCheckExtension(Boolean critical, Object value) + throws IOException { + + this.extensionId = PKIXExtensions.OCSPNoCheck_Id; + this.critical = critical.booleanValue(); + + // the value should be null, just ignore it here. + this.extensionValue = new byte[0]; + } + + /** + * Set the attribute value. + */ + public void set(String name, Object obj) throws IOException { + throw new IOException("No attribute is allowed by " + + "CertAttrSet:OCSPNoCheckExtension."); + } + + /** + * Get the attribute value. + */ + public Object get(String name) throws IOException { + throw new IOException("No attribute is allowed by " + + "CertAttrSet:OCSPNoCheckExtension."); + } + + /** + * Delete the attribute value. + */ + public void delete(String name) throws IOException { + throw new IOException("No attribute is allowed by " + + "CertAttrSet:OCSPNoCheckExtension."); + } + + /** + * Return an enumeration of names of attributes existing within this + * attribute. + */ + public Enumeration getElements() { + return (new AttributeNameEnumeration()).elements(); + } + + /** + * Return the name of this attribute. + */ + public String getName() { + return NAME; + } +} diff --git a/jdk/src/share/classes/sun/security/x509/OIDMap.java b/jdk/src/share/classes/sun/security/x509/OIDMap.java index bb7cffef343..f52fab3eeef 100644 --- a/jdk/src/share/classes/sun/security/x509/OIDMap.java +++ b/jdk/src/share/classes/sun/security/x509/OIDMap.java @@ -100,6 +100,8 @@ public class OIDMap { DeltaCRLIndicatorExtension.NAME; private static final String FRESHEST_CRL = ROOT + "." + FreshestCRLExtension.NAME; + private static final String OCSPNOCHECK = ROOT + "." + + OCSPNoCheckExtension.NAME; private static final int NetscapeCertType_data[] = { 2, 16, 840, 1, 113730, 1, 1 }; @@ -161,6 +163,8 @@ public class OIDMap { "sun.security.x509.DeltaCRLIndicatorExtension"); addInternal(FRESHEST_CRL, PKIXExtensions.FreshestCRL_Id, "sun.security.x509.FreshestCRLExtension"); + addInternal(OCSPNOCHECK, PKIXExtensions.OCSPNoCheck_Id, + "sun.security.x509.OCSPNoCheckExtension"); } /** diff --git a/jdk/src/share/classes/sun/security/x509/PKIXExtensions.java b/jdk/src/share/classes/sun/security/x509/PKIXExtensions.java index 78177944c08..f140c548551 100644 --- a/jdk/src/share/classes/sun/security/x509/PKIXExtensions.java +++ b/jdk/src/share/classes/sun/security/x509/PKIXExtensions.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-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 @@ -74,6 +74,8 @@ public class PKIXExtensions { private static final int AuthInfoAccess_data [] = { 1, 3, 6, 1, 5, 5, 7, 1, 1}; private static final int SubjectInfoAccess_data [] = { 1, 3, 6, 1, 5, 5, 7, 1, 11}; private static final int FreshestCRL_data [] = { 2, 5, 29, 46 }; + private static final int OCSPNoCheck_data [] = { 1, 3, 6, 1, 5, 5, 7, + 48, 1, 5}; /** * Identifies the particular public key used to sign the certificate. @@ -216,6 +218,12 @@ public class PKIXExtensions { */ public static final ObjectIdentifier FreshestCRL_Id; + /** + * Identifies the OCSP client can trust the responder for the + * lifetime of the responder's certificate. + */ + public static final ObjectIdentifier OCSPNoCheck_Id; + static { AuthorityKey_Id = ObjectIdentifier.newInternal(AuthorityKey_data); SubjectKey_Id = ObjectIdentifier.newInternal(SubjectKey_data); @@ -257,5 +265,6 @@ public class PKIXExtensions { SubjectInfoAccess_Id = ObjectIdentifier.newInternal(SubjectInfoAccess_data); FreshestCRL_Id = ObjectIdentifier.newInternal(FreshestCRL_data); + OCSPNoCheck_Id = ObjectIdentifier.newInternal(OCSPNoCheck_data); } } From 8e6208656a3b6bcf93248f35fa3e71dd6122dbea Mon Sep 17 00:00:00 2001 From: Hiroshi Yamauchi Date: Mon, 16 Mar 2009 11:46:26 -0700 Subject: [PATCH 28/75] 6812600: The miter line join decoration isn't rendered properly Reviewed-by: avu, flar --- .../java2d/pisces/PiscesRenderingEngine.java | 1 + jdk/test/sun/pisces/JoinMiterTest.java | 48 +++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 jdk/test/sun/pisces/JoinMiterTest.java diff --git a/jdk/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java b/jdk/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java index 7f55e886c69..12296daad2c 100644 --- a/jdk/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java +++ b/jdk/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java @@ -245,6 +245,7 @@ public class PiscesRenderingEngine extends RenderingEngine { FloatToS15_16(coords[1])); break; case PathIterator.SEG_CLOSE: + lsink.lineJoin(); lsink.close(); break; default: diff --git a/jdk/test/sun/pisces/JoinMiterTest.java b/jdk/test/sun/pisces/JoinMiterTest.java new file mode 100644 index 00000000000..567526b66e9 --- /dev/null +++ b/jdk/test/sun/pisces/JoinMiterTest.java @@ -0,0 +1,48 @@ +/* + * 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 + * @summary Pass if no RuntimeException. + * @bug 6812600 + */ +import java.awt.*; +import java.awt.image.BufferedImage; + +public class JoinMiterTest { + + public static void main(String[] args) throws Exception { + BufferedImage image = new BufferedImage(200, 200, +BufferedImage.TYPE_INT_RGB); + Graphics2D g = image.createGraphics(); + g.setPaint(Color.WHITE); + g.fill(new Rectangle(image.getWidth(), image.getHeight())); + g.translate(25, 100); + g.setPaint(Color.BLACK); + g.setStroke(new BasicStroke(20, BasicStroke.CAP_BUTT, + BasicStroke.JOIN_MITER)); + g.draw(new Polygon(new int[] {0, 150, 0}, new int[] {75, 0, -75}, 3)); + if (image.getRGB(16, 10) == Color.WHITE.getRGB()) { + throw new RuntimeException("Miter is not rendered."); + } + } +} From 6a44e920f6bf1f66d7ecff817763f35052d7e1ea Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan Date: Tue, 17 Mar 2009 11:54:13 +0800 Subject: [PATCH 29/75] 6383095: CRL revoked certificate failures masked by OCSP failures Remove the mask if certificate revoked Reviewed-by: mullan --- .../certpath/PKIXMasterCertPathValidator.java | 14 +- .../CertPathValidator/OCSP/FailoverToCRL.java | 265 ++++++++++++++++++ 2 files changed, 274 insertions(+), 5 deletions(-) create mode 100644 jdk/test/java/security/cert/CertPathValidator/OCSP/FailoverToCRL.java diff --git a/jdk/src/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java b/jdk/src/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java index d5f12168dda..7c3bfc37843 100644 --- a/jdk/src/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java +++ b/jdk/src/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-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 @@ -143,11 +143,15 @@ class PKIXMasterCertPathValidator { } } catch (CertPathValidatorException cpve) { - // Throw the saved OCSP exception - // (when the CRL check has also failed) + // Throw the saved OCSP exception unless the CRL + // checker has determined that the cert is revoked if (ocspCause != null && - currChecker instanceof CrlRevocationChecker) { - throw ocspCause; + currChecker instanceof CrlRevocationChecker) { + if (cpve.getReason() == BasicReason.REVOKED) { + throw cpve; + } else { + throw ocspCause; + } } /* * Handle failover from OCSP to CRLs diff --git a/jdk/test/java/security/cert/CertPathValidator/OCSP/FailoverToCRL.java b/jdk/test/java/security/cert/CertPathValidator/OCSP/FailoverToCRL.java new file mode 100644 index 00000000000..56367cd2ae3 --- /dev/null +++ b/jdk/test/java/security/cert/CertPathValidator/OCSP/FailoverToCRL.java @@ -0,0 +1,265 @@ +/* + * 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 6383095 + * @summary CRL revoked certificate failures masked by OCSP failures + * + * Note that the certificate validity is from Mar 16 14:55:35 2009 GMT to + * Dec 1 14:55:35 2028 GMT, please update it with newer certificate if + * expires. + * + * @author Xuelei Fan + */ + +/* + * Certificates used in the test. + * + * end entity certificate: + * Data: + * Version: 3 (0x2) + * Serial Number: 25 (0x19) + * Signature Algorithm: md5WithRSAEncryption + * Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org + * Validity + * Not Before: Mar 16 14:55:35 2009 GMT + * Not After : Dec 1 14:55:35 2028 GMT + * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org, OU=SSL-Client, + * CN=localhost + * Subject Public Key Info: + * Public Key Algorithm: rsaEncryption + * RSA Public Key: (1024 bit) + * Modulus (1024 bit): + * 00:bb:f0:40:36:ac:26:54:4e:f4:a3:5a:00:2f:69: + * 21:6f:b9:7a:3a:93:ec:a2:f6:e1:8e:c7:63:d8:2f: + * 12:30:99:2e:b0:f2:8f:f8:27:2d:24:78:28:84:f7: + * 01:bf:8d:44:79:dd:3b:d2:55:f3:ce:3c:b2:5b:21: + * 7d:ef:fd:33:4a:b1:a3:ff:c6:c8:9b:b9:0f:7c:41: + * 35:97:f9:db:3a:05:60:05:15:af:59:17:92:a3:10: + * ad:16:1c:e4:07:53:af:a8:76:a2:56:2a:92:d3:f9: + * 28:e0:78:cf:5e:1f:48:ab:5c:19:dd:e1:67:43:ba: + * 75:8d:f5:82:ac:43:92:44:1b + * Exponent: 65537 (0x10001) + * X509v3 extensions: + * X509v3 Basic Constraints: + * CA:FALSE + * X509v3 Key Usage: + * Digital Signature, Non Repudiation, Key Encipherment + * X509v3 Subject Key Identifier: + * CD:BB:C8:85:AA:91:BD:FD:1D:BE:CD:67:7C:FF:B3:E9:4C:A8:22:E6 + * X509v3 Authority Key Identifier: + * keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 + * Signature Algorithm: md5WithRSAEncryption + * + * + * trusted certificate authority: + * Data: + * Version: 3 (0x2) + * Serial Number: 0 (0x0) + * Signature Algorithm: md5WithRSAEncryption + * Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org + * Validity + * Not Before: Dec 8 02:43:36 2008 GMT + * Not After : Aug 25 02:43:36 2028 GMT + * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org + * Subject Public Key Info: + * Public Key Algorithm: rsaEncryption + * RSA Public Key: (1024 bit) + * Modulus (1024 bit): + * 00:cb:c4:38:20:07:be:88:a7:93:b0:a1:43:51:2d: + * d7:8e:85:af:54:dd:ad:a2:7b:23:5b:cf:99:13:53: + * 99:45:7d:ee:6d:ba:2d:bf:e3:ad:6e:3d:9f:1a:f9: + * 03:97:e0:17:55:ae:11:26:57:de:01:29:8e:05:3f: + * 21:f7:e7:36:e8:2e:37:d7:48:ac:53:d6:60:0e:c7: + * 50:6d:f6:c5:85:f7:8b:a6:c5:91:35:72:3c:94:ee: + * f1:17:f0:71:e3:ec:1b:ce:ca:4e:40:42:b0:6d:ee: + * 6a:0e:d6:e5:ad:3c:0f:c9:ba:82:4f:78:f8:89:97: + * 89:2a:95:12:4c:d8:09:2a:e9 + * Exponent: 65537 (0x10001) + * X509v3 extensions: + * X509v3 Subject Key Identifier: + * FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 + * X509v3 Authority Key Identifier: + * keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 + * DirName:/C=US/ST=Some-State/L=Some-City/O=Some-Org + * X509v3 Basic Constraints: + * CA:TRUE + * Signature Algorithm: md5WithRSAEncryption + * + * CRL: + * Certificate Revocation List (CRL): + * Version 2 (0x1) + * Signature Algorithm: md5WithRSAEncryption + * Issuer: /C=US/ST=Some-State/L=Some-City/O=Some-Org + * Last Update: Mar 16 16:27:14 2009 GMT + * Next Update: May 15 16:27:14 2028 GMT + * CRL extensions: + * X509v3 CRL Number: + * 2 + * Revoked Certificates: + * Serial Number: 19 + * Revocation Date: Mar 16 16:22:08 2009 GMT + * CRL entry extensions: + * X509v3 CRL Reason Code: + * Superseded + * Signature Algorithm: md5WithRSAEncryption + */ + +import java.io.*; +import java.net.SocketException; +import java.util.*; +import java.security.Security; +import java.security.cert.*; +import java.security.InvalidAlgorithmParameterException; +import java.security.cert.CertPathValidatorException.BasicReason; + +public class FailoverToCRL { + + static String trusedCertStr = + "-----BEGIN CERTIFICATE-----\n" + + "MIICrDCCAhWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" + + "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" + + "EwhTb21lLU9yZzAeFw0wODEyMDgwMjQzMzZaFw0yODA4MjUwMjQzMzZaMEkxCzAJ\n" + + "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" + + "dHkxETAPBgNVBAoTCFNvbWUtT3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB\n" + + "gQDLxDggB76Ip5OwoUNRLdeOha9U3a2ieyNbz5kTU5lFfe5tui2/461uPZ8a+QOX\n" + + "4BdVrhEmV94BKY4FPyH35zboLjfXSKxT1mAOx1Bt9sWF94umxZE1cjyU7vEX8HHj\n" + + "7BvOyk5AQrBt7moO1uWtPA/JuoJPePiJl4kqlRJM2Akq6QIDAQABo4GjMIGgMB0G\n" + + "A1UdDgQWBBT6uVG/TOfZhpgz+efLHvEzSfeoFDBxBgNVHSMEajBogBT6uVG/TOfZ\n" + + "hpgz+efLHvEzSfeoFKFNpEswSTELMAkGA1UEBhMCVVMxEzARBgNVBAgTClNvbWUt\n" + + "U3RhdGUxEjAQBgNVBAcTCVNvbWUtQ2l0eTERMA8GA1UEChMIU29tZS1PcmeCAQAw\n" + + "DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBcIm534U123Hz+rtyYO5uA\n" + + "ofd81G6FnTfEAV8Kw9fGyyEbQZclBv34A9JsFKeMvU4OFIaixD7nLZ/NZ+IWbhmZ\n" + + "LovmJXyCkOufea73pNiZ+f/4/ScZaIlM/PRycQSqbFNd4j9Wott+08qxHPLpsf3P\n" + + "6Mvf0r1PNTY2hwTJLJmKtg==\n" + + "-----END CERTIFICATE-----"; + + static String targetCertStr = + "-----BEGIN CERTIFICATE-----\n" + + "MIICizCCAfSgAwIBAgIBGTANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" + + "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" + + "EwhTb21lLU9yZzAeFw0wOTAzMTYxNDU1MzVaFw0yODEyMDExNDU1MzVaMHIxCzAJ\n" + + "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" + + "dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtQ2xpZW50MRIwEAYD\n" + + "VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALvwQDas\n" + + "JlRO9KNaAC9pIW+5ejqT7KL24Y7HY9gvEjCZLrDyj/gnLSR4KIT3Ab+NRHndO9JV\n" + + "8848slshfe/9M0qxo//GyJu5D3xBNZf52zoFYAUVr1kXkqMQrRYc5AdTr6h2olYq\n" + + "ktP5KOB4z14fSKtcGd3hZ0O6dY31gqxDkkQbAgMBAAGjWjBYMAkGA1UdEwQCMAAw\n" + + "CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTNu8iFqpG9/R2+zWd8/7PpTKgi5jAfBgNV\n" + + "HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDANBgkqhkiG9w0BAQQFAAOBgQBv\n" + + "p7JjCDOrMBNun46xs4Gz7Y4ygM5VHaFP0oO7369twvRSu0pCuIdZd5OIMPFeRqQw\n" + + "PA68ZdhYVR0pG5W7isV+jB+Dfge/IOgOA85sZ/6FlP3PBRW+YMQKKdRr5So3ook9\n" + + "PimQ7rbxRAofPECv20IUKFBbOUkU+gFcn+WbTKYxBw==\n" + + "-----END CERTIFICATE-----"; + + static String crlStr = + "-----BEGIN X509 CRL-----\n" + + "MIIBRTCBrwIBATANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzETMBEGA1UE\n" + + "CBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQKEwhTb21l\n" + + "LU9yZxcNMDkwMzE2MTYyNzE0WhcNMjgwNTE1MTYyNzE0WjAiMCACARkXDTA5MDMx\n" + + "NjE2MjIwOFowDDAKBgNVHRUEAwoBBKAOMAwwCgYDVR0UBAMCAQIwDQYJKoZIhvcN\n" + + "AQEEBQADgYEAMixJI9vBwYpOGosn46+T/MTEtlm2S5pIVT/xPDrHkCPfw8l4Zrgp\n" + + "dGPuUkglWdrGdxY9MNRUj2YFNfdZi6zZ7JF6XbkDHYOAKYgPDJRjS/0VcBntn5RJ\n" + + "sQfZsBqc9fFSP8gknRRn3LT41kr9xNRxTT1t3YYjv7J3zkMYyInqeUA=\n" + + "-----END X509 CRL-----"; + + + private static CertPath generateCertificatePath() + throws CertificateException { + // generate certificate from cert strings + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + ByteArrayInputStream is = + new ByteArrayInputStream(targetCertStr.getBytes()); + Certificate targetCert = cf.generateCertificate(is); + + // generate certification path + List list = Arrays.asList(new Certificate[] {targetCert}); + + return cf.generateCertPath(list); + } + + private static Set generateTrustAnchors() + throws CertificateException { + // generate certificate from cert string + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + ByteArrayInputStream is = + new ByteArrayInputStream(trusedCertStr.getBytes()); + Certificate trusedCert = cf.generateCertificate(is); + + // generate a trust anchor + TrustAnchor anchor = new TrustAnchor((X509Certificate)trusedCert, null); + + return Collections.singleton(anchor); + } + + private static CertStore generateCertificateStore() throws Exception { + // generate CRL from CRL string + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + ByteArrayInputStream is = + new ByteArrayInputStream(crlStr.getBytes()); + + // generate a cert store + Collection crls = cf.generateCRLs(is); + return CertStore.getInstance("Collection", + new CollectionCertStoreParameters(crls)); + } + + public static void main(String args[]) throws Exception { + CertPath path = generateCertificatePath(); + Set anchors = generateTrustAnchors(); + CertStore crls = generateCertificateStore(); + + PKIXParameters params = new PKIXParameters(anchors); + + // add the CRL store + params.addCertStore(crls); + + // Activate certificate revocation checking + params.setRevocationEnabled(true); + + // Activate OCSP + Security.setProperty("ocsp.enable", "true"); + System.setProperty("com.sun.security.enableCRLDP", "true"); + + // Ensure that the ocsp.responderURL property is not set. + if (Security.getProperty("ocsp.responderURL") != null) { + throw new + Exception("The ocsp.responderURL property must not be set"); + } + + CertPathValidator validator = CertPathValidator.getInstance("PKIX"); + + try { + validator.validate(path, params); + } catch (CertPathValidatorException cpve) { + if (cpve.getReason() != BasicReason.REVOKED) { + throw new Exception( + "unexpect exception, should be a REVOKED CPVE", cpve); + } + } + } +} From 61485906a3089e840f40798d171cdb7216bafcb1 Mon Sep 17 00:00:00 2001 From: Tim Bell Date: Tue, 17 Mar 2009 11:28:24 -0700 Subject: [PATCH 30/75] 6814592: Legal notice repair needed in langtools/test/tools/javap/T4884240.java Reviewed-by: jjg --- langtools/test/tools/javap/T4884240.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/langtools/test/tools/javap/T4884240.java b/langtools/test/tools/javap/T4884240.java index 93d4cc9361c..f2f36167760 100644 --- a/langtools/test/tools/javap/T4884240.java +++ b/langtools/test/tools/javap/T4884240.java @@ -16,7 +16,7 @@ * * 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-15301 USA. + * 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 From a787d51eea2fc9dfa9272e4ca90d018c2833a80f Mon Sep 17 00:00:00 2001 From: Tim Bell Date: Tue, 17 Mar 2009 13:20:56 -0700 Subject: [PATCH 31/75] 6814587: Legal notice repair needed in jdk/src/share/classes/java/nio 6814590: Legal notice repair needed in jdk/test/java/awt/Frame/FrameSize/TestFrameSize.java 6814591: Legal notice repair needed in jdk/test/javax/script/Test3.java Reviewed-by: alanb, xdono --- .../share/classes/java/nio/file/SecureDirectoryStream.java | 2 +- .../classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java | 2 +- .../sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java | 2 +- jdk/test/java/awt/Frame/FrameSize/TestFrameSize.java | 4 ++++ jdk/test/javax/script/Test3.java | 1 - 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/jdk/src/share/classes/java/nio/file/SecureDirectoryStream.java b/jdk/src/share/classes/java/nio/file/SecureDirectoryStream.java index 11df095ceb3..b2555c14185 100644 --- a/jdk/src/share/classes/java/nio/file/SecureDirectoryStream.java +++ b/jdk/src/share/classes/java/nio/file/SecureDirectoryStream.java @@ -5,7 +5,7 @@ * 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. Sun designates this - * particular file as subject to the "Classname" exception as provided + * particular file as subject to the "Classpath" exception as provided * by Sun in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT diff --git a/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java b/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java index 702b28cbbeb..78ed152d3a1 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java +++ b/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java @@ -16,7 +16,7 @@ * * 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 conne02110-1301 USA. + * 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 diff --git a/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java index fe9920c15cc..d1f8c9307d5 100644 --- a/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java +++ b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java @@ -16,7 +16,7 @@ * * 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 conne02110-1301 USA. + * 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 diff --git a/jdk/test/java/awt/Frame/FrameSize/TestFrameSize.java b/jdk/test/java/awt/Frame/FrameSize/TestFrameSize.java index f8a98ea3216..b220ec5cc01 100644 --- a/jdk/test/java/awt/Frame/FrameSize/TestFrameSize.java +++ b/jdk/test/java/awt/Frame/FrameSize/TestFrameSize.java @@ -15,6 +15,10 @@ * 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. */ /* diff --git a/jdk/test/javax/script/Test3.java b/jdk/test/javax/script/Test3.java index 8aa876ba24a..66fa23af07a 100644 --- a/jdk/test/javax/script/Test3.java +++ b/jdk/test/javax/script/Test3.java @@ -4,7 +4,6 @@ * * 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 From e85a4d85368f38ede58ac8bf35f46959221c47dd Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Wed, 18 Mar 2009 17:37:39 -0700 Subject: [PATCH 32/75] 6817246: Redundant call to set InetAddressCachePolicy to FOREVER if not set during initialization Remove InetAddressCachePolicy.setIfNotSet call from System.setSecurityManager0 Reviewed-by: alanb, jccollet --- jdk/src/share/classes/java/lang/System.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/jdk/src/share/classes/java/lang/System.java b/jdk/src/share/classes/java/lang/System.java index eb62b4087e9..68958dd0898 100644 --- a/jdk/src/share/classes/java/lang/System.java +++ b/jdk/src/share/classes/java/lang/System.java @@ -34,7 +34,6 @@ import java.security.AllPermission; import java.nio.channels.Channel; import java.nio.channels.spi.SelectorProvider; import sun.nio.ch.Interruptible; -import sun.net.InetAddressCachePolicy; import sun.reflect.Reflection; import sun.security.util.SecurityConstants; import sun.reflect.annotation.AnnotationType; @@ -310,7 +309,6 @@ public final class System { } security = s; - InetAddressCachePolicy.setIfNotSet(InetAddressCachePolicy.FOREVER); } /** From 827d42556046082a905e321e4ff2eadca747615f Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Thu, 19 Mar 2009 11:17:06 +0800 Subject: [PATCH 33/75] 6819272: keytool -importcert should read the whole input Reviewed-by: xuelei --- .../classes/sun/security/tools/KeyTool.java | 12 ++++ .../security/tools/keytool/importreadall.sh | 62 +++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 jdk/test/sun/security/tools/keytool/importreadall.sh diff --git a/jdk/src/share/classes/sun/security/tools/KeyTool.java b/jdk/src/share/classes/sun/security/tools/KeyTool.java index ca2d6a384ab..a3aa50f435d 100644 --- a/jdk/src/share/classes/sun/security/tools/KeyTool.java +++ b/jdk/src/share/classes/sun/security/tools/KeyTool.java @@ -875,6 +875,18 @@ public final class KeyTool { if (filename != null) { inStream = new FileInputStream(filename); } + // Read the full stream before feeding to X509Factory, + // otherwise, keytool -gencert | keytool -importcert + // might not work properly, since -gencert is slow + // and there's no data in the pipe at the beginning. + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + byte[] b = new byte[4096]; + while (true) { + int len = inStream.read(b); + if (len < 0) break; + bout.write(b, 0, len); + } + inStream = new ByteArrayInputStream(bout.toByteArray()); try { String importAlias = (alias!=null)?alias:keyAlias; if (keyStore.entryInstanceOf(importAlias, KeyStore.PrivateKeyEntry.class)) { diff --git a/jdk/test/sun/security/tools/keytool/importreadall.sh b/jdk/test/sun/security/tools/keytool/importreadall.sh new file mode 100644 index 00000000000..6c0c65dedc7 --- /dev/null +++ b/jdk/test/sun/security/tools/keytool/importreadall.sh @@ -0,0 +1,62 @@ +# +# 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 6819272 +# @summary keytool -importcert should read the whole input +# +# @run shell importreadall.sh + +# set a few environment variables so that the shell-script can run stand-alone +# in the source directory +if [ "${TESTSRC}" = "" ] ; then + TESTSRC="." +fi + +if [ "${TESTJAVA}" = "" ] ; then + JAVA_CMD=`which java` + TESTJAVA=`dirname $JAVA_CMD`/.. +fi + +# set platform-dependent variables +OS=`uname -s` +case "$OS" in + Windows_* ) + FS="\\" + ;; + * ) + FS="/" + ;; +esac + +KEYTOOL="${TESTJAVA}${FS}bin${FS}keytool -keystore importreadall.jks -storepass changeit -keypass changeit" + +# In case the test is run twice in the same directory + +$KEYTOOL -delete -alias a +$KEYTOOL -delete -alias ca +$KEYTOOL -genkeypair -alias a -dname CN=a || exit 1 +$KEYTOOL -genkeypair -alias ca -dname CN=ca || exit 2 +$KEYTOOL -certreq -alias a | $KEYTOOL -gencert -alias ca | $KEYTOOL -importcert -alias a + +exit $? From fd5bc7200533a2c35dcaafd04df7008dcb9c64fd Mon Sep 17 00:00:00 2001 From: Bhavesh Patel Date: Thu, 19 Mar 2009 19:00:54 -0700 Subject: [PATCH 34/75] 6786688: Javadoc HTML WCAG 2.0 accessibility issues in standard doclet - Table must have captions and headers Reviewed-by: jjg --- .../formats/html/AbstractMemberWriter.java | 32 +- .../html/AbstractPackageIndexWriter.java | 12 +- ...nnotationTypeOptionalMemberWriterImpl.java | 24 +- ...nnotationTypeRequiredMemberWriterImpl.java | 24 +- .../doclets/formats/html/ClassUseWriter.java | 133 ++--- .../html/ConstantsSummaryWriterImpl.java | 21 +- .../formats/html/ConstructorWriterImpl.java | 31 +- .../formats/html/DeprecatedListWriter.java | 34 +- .../formats/html/EnumConstantWriterImpl.java | 20 +- .../doclets/formats/html/FieldWriterImpl.java | 21 +- .../formats/html/HtmlDocletWriter.java | 43 ++ .../formats/html/MethodWriterImpl.java | 21 +- .../formats/html/NestedClassWriterImpl.java | 32 +- .../formats/html/PackageIndexFrameWriter.java | 2 +- .../formats/html/PackageIndexWriter.java | 17 +- .../formats/html/PackageUseWriter.java | 21 +- .../formats/html/PackageWriterImpl.java | 27 +- .../formats/html/StylesheetWriter.java | 8 + .../formats/html/SubWriterHolderWriter.java | 10 +- .../formats/html/markup/HtmlWriter.java | 96 ++++ .../html/resources/standard.properties | 12 + .../toolkit/PackageSummaryWriter.java | 2 +- .../builders/PackageSummaryBuilder.java | 79 ++- .../toolkit/resources/doclets.properties | 33 ++ .../javadoc/testHeadings/TestHeadings.java | 31 +- .../testHtmlStrongTag/TestHtmlStrongTag.java | 13 +- .../testHtmlTableTags/TestHtmlTableTags.java | 478 ++++++++++++++++++ .../javadoc/testHtmlTableTags/pkg1/C1.java | 81 +++ .../javadoc/testHtmlTableTags/pkg1/I1.java | 48 ++ .../testHtmlTableTags/pkg1/package-info.java | 27 + .../javadoc/testHtmlTableTags/pkg2/C2.java | 73 +++ .../javadoc/testHtmlTableTags/pkg2/C3.java | 40 ++ .../javadoc/testHtmlTableTags/pkg2/C4.java | 35 ++ .../testHtmlTableTags/pkg2/package-info.java | 27 + .../TestNewLanguageFeatures.java | 274 +++++++--- .../TestSummaryHeading.java | 3 +- 36 files changed, 1659 insertions(+), 226 deletions(-) create mode 100644 langtools/test/com/sun/javadoc/testHtmlTableTags/TestHtmlTableTags.java create mode 100644 langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/C1.java create mode 100644 langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/I1.java create mode 100644 langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/package-info.java create mode 100644 langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C2.java create mode 100644 langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C3.java create mode 100644 langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C4.java create mode 100644 langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/package-info.java diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractMemberWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractMemberWriter.java index d6c298f13da..273b42558ed 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractMemberWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractMemberWriter.java @@ -60,7 +60,11 @@ public abstract class AbstractMemberWriter { /*** abstracts ***/ - public abstract void printSummaryLabel(ClassDoc cd); + public abstract void printSummaryLabel(); + + public abstract void printTableSummary(); + + public abstract void printSummaryTableHeader(ProgramElementDoc member); public abstract void printInheritedSummaryLabel(ClassDoc cd); @@ -342,12 +346,13 @@ public abstract class AbstractMemberWriter { * format for listing the API. Call methods from the sub-class to complete * the generation. */ - protected void printDeprecatedAPI(List deprmembers, String headingKey) { + protected void printDeprecatedAPI(List deprmembers, String headingKey, String tableSummary, String[] tableHeader) { if (deprmembers.size() > 0) { - writer.tableIndexSummary(); - writer.tableHeaderStart("#CCCCFF"); - writer.strongText(headingKey); - writer.tableHeaderEnd(); + writer.tableIndexSummary(tableSummary); + writer.tableCaptionStart(); + writer.printText(headingKey); + writer.tableCaptionEnd(); + writer.summaryTableHeader(tableHeader, "col"); for (int i = 0; i < deprmembers.size(); i++) { ProgramElementDoc member =(ProgramElementDoc)deprmembers.get(i); writer.trBgcolorStyle("white", "TableRowColor"); @@ -370,19 +375,26 @@ public abstract class AbstractMemberWriter { /** * Print use info. */ - protected void printUseInfo(List mems, String heading) { + protected void printUseInfo(List mems, String heading, String tableSummary) { if (mems == null) { return; } List members = mems; + boolean printedUseTableHeader = false; if (members.size() > 0) { - writer.tableIndexSummary(); - writer.tableUseInfoHeaderStart("#CCCCFF"); + writer.tableIndexSummary(tableSummary); + writer.tableSubCaptionStart(); writer.print(heading); - writer.tableHeaderEnd(); + writer.tableCaptionEnd(); for (Iterator it = members.iterator(); it.hasNext(); ) { ProgramElementDoc pgmdoc = it.next(); ClassDoc cd = pgmdoc.containingClass(); + if (!printedUseTableHeader) { + // Passing ProgramElementDoc helps decides printing + // interface or class header in case of nested classes. + this.printSummaryTableHeader(pgmdoc); + printedUseTableHeader = true; + } writer.printSummaryLinkType(this, pgmdoc); if (cd != null && !(pgmdoc instanceof ConstructorDoc) diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractPackageIndexWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractPackageIndexWriter.java index 36742cf7f95..b743aeacd2d 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractPackageIndexWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractPackageIndexWriter.java @@ -35,6 +35,7 @@ import java.util.*; * generate overview-frame.html as well as overview-summary.html. * * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) */ public abstract class AbstractPackageIndexWriter extends HtmlDocletWriter { @@ -61,7 +62,7 @@ public abstract class AbstractPackageIndexWriter extends HtmlDocletWriter { protected abstract void printOverviewHeader(); - protected abstract void printIndexHeader(String text); + protected abstract void printIndexHeader(String text, String tableSummary); protected abstract void printIndexRow(PackageDoc pkg); @@ -101,7 +102,10 @@ public abstract class AbstractPackageIndexWriter extends HtmlDocletWriter { * Generate the frame or non-frame package index. */ protected void generateIndex() { - printIndexContents(packages, "doclet.Package_Summary"); + printIndexContents(packages, "doclet.Package_Summary", + configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Package_Summary"), + configuration.getText("doclet.packages"))); } /** @@ -111,10 +115,10 @@ public abstract class AbstractPackageIndexWriter extends HtmlDocletWriter { * @param packages Array of packages to be documented. * @param text String which will be used as the heading. */ - protected void printIndexContents(PackageDoc[] packages, String text) { + protected void printIndexContents(PackageDoc[] packages, String text, String tableSummary) { if (packages.length > 0) { Arrays.sort(packages); - printIndexHeader(text); + printIndexHeader(text, tableSummary); printAllClassesPackagesLink(); for(int i = 0; i < packages.length; i++) { if (packages[i] != null) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeOptionalMemberWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeOptionalMemberWriterImpl.java index 1442e3ccf0c..5bf2f8e19fe 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeOptionalMemberWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeOptionalMemberWriterImpl.java @@ -34,6 +34,7 @@ import com.sun.tools.doclets.internal.toolkit.*; * Writes annotation type optional member documentation in HTML format. * * @author Jamie Ho + * @author Bhavesh Patel (Modified) */ public class AnnotationTypeOptionalMemberWriterImpl extends AnnotationTypeRequiredMemberWriterImpl @@ -89,8 +90,27 @@ public class AnnotationTypeOptionalMemberWriterImpl extends /** * {@inheritDoc} */ - public void printSummaryLabel(ClassDoc cd) { - writer.strongText("doclet.Annotation_Type_Optional_Member_Summary"); + public void printSummaryLabel() { + writer.printText("doclet.Annotation_Type_Optional_Member_Summary"); + } + + /** + * {@inheritDoc} + */ + public void printTableSummary() { + writer.tableIndexSummary(configuration().getText("doclet.Member_Table_Summary", + configuration().getText("doclet.Annotation_Type_Optional_Member_Summary"), + configuration().getText("doclet.annotation_type_optional_members"))); + } + + public void printSummaryTableHeader(ProgramElementDoc member) { + String[] header = new String[] { + writer.getModifierTypeHeader(), + configuration().getText("doclet.0_and_1", + configuration().getText("doclet.Annotation_Type_Optional_Member"), + configuration().getText("doclet.Description")) + }; + writer.summaryTableHeader(header, "col"); } /** diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeRequiredMemberWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeRequiredMemberWriterImpl.java index 01e517ce426..9b745c68187 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeRequiredMemberWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeRequiredMemberWriterImpl.java @@ -34,6 +34,7 @@ import com.sun.tools.doclets.internal.toolkit.*; * Writes annotation type required member documentation in HTML format. * * @author Jamie Ho + * @author Bhavesh Patel (Modified) */ public class AnnotationTypeRequiredMemberWriterImpl extends AbstractMemberWriter implements AnnotationTypeRequiredMemberWriter, MemberSummaryWriter { @@ -178,8 +179,27 @@ public class AnnotationTypeRequiredMemberWriterImpl extends AbstractMemberWriter /** * {@inheritDoc} */ - public void printSummaryLabel(ClassDoc cd) { - writer.strongText("doclet.Annotation_Type_Required_Member_Summary"); + public void printSummaryLabel() { + writer.printText("doclet.Annotation_Type_Required_Member_Summary"); + } + + /** + * {@inheritDoc} + */ + public void printTableSummary() { + writer.tableIndexSummary(configuration().getText("doclet.Member_Table_Summary", + configuration().getText("doclet.Annotation_Type_Required_Member_Summary"), + configuration().getText("doclet.annotation_type_required_members"))); + } + + public void printSummaryTableHeader(ProgramElementDoc member) { + String[] header = new String[] { + writer.getModifierTypeHeader(), + configuration().getText("doclet.0_and_1", + configuration().getText("doclet.Annotation_Type_Required_Member"), + configuration().getText("doclet.Description")) + }; + writer.summaryTableHeader(header, "col"); } /** diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassUseWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassUseWriter.java index 73d957e3c4e..6baec7af9d8 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassUseWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassUseWriter.java @@ -34,6 +34,7 @@ import java.util.*; * Generate class usage information. * * @author Robert G. Field + * @author Bhavesh Patel (Modified) */ public class ClassUseWriter extends SubWriterHolderWriter { @@ -65,6 +66,13 @@ public class ClassUseWriter extends SubWriterHolderWriter { final ConstructorWriterImpl constrSubWriter; final FieldWriterImpl fieldSubWriter; final NestedClassWriterImpl classSubWriter; + // Summary for various use tables. + final String classUseTableSummary; + final String subclassUseTableSummary; + final String subinterfaceUseTableSummary; + final String fieldUseTableSummary; + final String methodUseTableSummary; + final String constructorUseTableSummary; /** @@ -116,6 +124,18 @@ public class ClassUseWriter extends SubWriterHolderWriter { constrSubWriter = new ConstructorWriterImpl(this); fieldSubWriter = new FieldWriterImpl(this); classSubWriter = new NestedClassWriterImpl(this); + classUseTableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.classes")); + subclassUseTableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.subclasses")); + subinterfaceUseTableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.subinterfaces")); + fieldUseTableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.fields")); + methodUseTableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.methods")); + constructorUseTableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.constructors")); } /** @@ -213,12 +233,13 @@ public class ClassUseWriter extends SubWriterHolderWriter { } protected void generatePackageList() throws IOException { - tableIndexSummary(); - tableHeaderStart("#CCCCFF"); + tableIndexSummary(useTableSummary); + tableCaptionStart(); printText("doclet.ClassUse_Packages.that.use.0", getLink(new LinkInfoImpl(LinkInfoImpl.CONTEXT_CLASS_USE_HEADER, classdoc, false))); - tableHeaderEnd(); + tableCaptionEnd(); + summaryTableHeader(packageTableHeader, "col"); for (Iterator it = pkgSet.iterator(); it.hasNext();) { PackageDoc pkg = it.next(); @@ -234,12 +255,13 @@ public class ClassUseWriter extends SubWriterHolderWriter { pkgToPackageAnnotations == null || pkgToPackageAnnotations.size() == 0) return; - tableIndexSummary(); - tableHeaderStart("#CCCCFF"); + tableIndexSummary(useTableSummary); + tableCaptionStart(); printText("doclet.ClassUse_PackageAnnotation", getLink(new LinkInfoImpl(LinkInfoImpl.CONTEXT_CLASS_USE_HEADER, classdoc, false))); - tableHeaderEnd(); + tableCaptionEnd(); + summaryTableHeader(packageTableHeader, "col"); for (Iterator it = pkgToPackageAnnotations.iterator(); it.hasNext();) { PackageDoc pkg = it.next(); trBgcolorStyle("white", "TableRowColor"); @@ -300,83 +322,68 @@ public class ClassUseWriter extends SubWriterHolderWriter { LinkInfoImpl.CONTEXT_CLASS_USE_HEADER, classdoc, false)); String pkgLink = getPackageLink(pkg, Util.getPackageName(pkg), false); classSubWriter.printUseInfo(pkgToClassAnnotations.get(pkg.name()), - configuration.getText("doclet.ClassUse_Annotation", classLink, - pkgLink)); - + configuration.getText("doclet.ClassUse_Annotation", classLink, + pkgLink), classUseTableSummary); classSubWriter.printUseInfo(pkgToClassTypeParameter.get(pkg.name()), - configuration.getText("doclet.ClassUse_TypeParameter", classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_TypeParameter", classLink, + pkgLink), classUseTableSummary); classSubWriter.printUseInfo(pkgToSubclass.get(pkg.name()), - configuration.getText("doclet.ClassUse_Subclass", classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_Subclass", classLink, + pkgLink), subclassUseTableSummary); classSubWriter.printUseInfo(pkgToSubinterface.get(pkg.name()), - configuration.getText("doclet.ClassUse_Subinterface", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_Subinterface", classLink, + pkgLink), subinterfaceUseTableSummary); classSubWriter.printUseInfo(pkgToImplementingClass.get(pkg.name()), - configuration.getText("doclet.ClassUse_ImplementingClass", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_ImplementingClass", classLink, + pkgLink), classUseTableSummary); fieldSubWriter.printUseInfo(pkgToField.get(pkg.name()), - configuration.getText("doclet.ClassUse_Field", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_Field", classLink, + pkgLink), fieldUseTableSummary); fieldSubWriter.printUseInfo(pkgToFieldAnnotations.get(pkg.name()), - configuration.getText("doclet.ClassUse_FieldAnnotations", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_FieldAnnotations", classLink, + pkgLink), fieldUseTableSummary); fieldSubWriter.printUseInfo(pkgToFieldTypeParameter.get(pkg.name()), - configuration.getText("doclet.ClassUse_FieldTypeParameter", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_FieldTypeParameter", classLink, + pkgLink), fieldUseTableSummary); methodSubWriter.printUseInfo(pkgToMethodAnnotations.get(pkg.name()), - configuration.getText("doclet.ClassUse_MethodAnnotations", classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_MethodAnnotations", classLink, + pkgLink), methodUseTableSummary); methodSubWriter.printUseInfo(pkgToMethodParameterAnnotations.get(pkg.name()), - configuration.getText("doclet.ClassUse_MethodParameterAnnotations", classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_MethodParameterAnnotations", classLink, + pkgLink), methodUseTableSummary); methodSubWriter.printUseInfo(pkgToMethodTypeParameter.get(pkg.name()), - configuration.getText("doclet.ClassUse_MethodTypeParameter", classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_MethodTypeParameter", classLink, + pkgLink), methodUseTableSummary); methodSubWriter.printUseInfo(pkgToMethodReturn.get(pkg.name()), - configuration.getText("doclet.ClassUse_MethodReturn", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_MethodReturn", classLink, + pkgLink), methodUseTableSummary); methodSubWriter.printUseInfo(pkgToMethodReturnTypeParameter.get(pkg.name()), - configuration.getText("doclet.ClassUse_MethodReturnTypeParameter", classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_MethodReturnTypeParameter", classLink, + pkgLink), methodUseTableSummary); methodSubWriter.printUseInfo(pkgToMethodArgs.get(pkg.name()), - configuration.getText("doclet.ClassUse_MethodArgs", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_MethodArgs", classLink, + pkgLink), methodUseTableSummary); methodSubWriter.printUseInfo(pkgToMethodArgTypeParameter.get(pkg.name()), - configuration.getText("doclet.ClassUse_MethodArgsTypeParameters", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_MethodArgsTypeParameters", classLink, + pkgLink), methodUseTableSummary); methodSubWriter.printUseInfo(pkgToMethodThrows.get(pkg.name()), - configuration.getText("doclet.ClassUse_MethodThrows", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_MethodThrows", classLink, + pkgLink), methodUseTableSummary); constrSubWriter.printUseInfo(pkgToConstructorAnnotations.get(pkg.name()), - configuration.getText("doclet.ClassUse_ConstructorAnnotations", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_ConstructorAnnotations", classLink, + pkgLink), constructorUseTableSummary); constrSubWriter.printUseInfo(pkgToConstructorParameterAnnotations.get(pkg.name()), - configuration.getText("doclet.ClassUse_ConstructorParameterAnnotations", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_ConstructorParameterAnnotations", classLink, + pkgLink), constructorUseTableSummary); constrSubWriter.printUseInfo(pkgToConstructorArgs.get(pkg.name()), - configuration.getText("doclet.ClassUse_ConstructorArgs", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_ConstructorArgs", classLink, + pkgLink), constructorUseTableSummary); constrSubWriter.printUseInfo(pkgToConstructorArgTypeParameter.get(pkg.name()), - configuration.getText("doclet.ClassUse_ConstructorArgsTypeParameters", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_ConstructorArgsTypeParameters", classLink, + pkgLink), constructorUseTableSummary); constrSubWriter.printUseInfo(pkgToConstructorThrows.get(pkg.name()), - configuration.getText("doclet.ClassUse_ConstructorThrows", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_ConstructorThrows", classLink, + pkgLink), constructorUseTableSummary); } /** diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstantsSummaryWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstantsSummaryWriterImpl.java index d64b2656d59..ddf51063a0a 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstantsSummaryWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstantsSummaryWriterImpl.java @@ -35,6 +35,7 @@ import java.util.*; * Write the Constants Summary Page in HTML format. * * @author Jamie Ho + * @author Bhavesh Patel (Modified) * @since 1.4 */ public class ConstantsSummaryWriterImpl extends HtmlDocletWriter @@ -50,6 +51,10 @@ public class ConstantsSummaryWriterImpl extends HtmlDocletWriter */ private ClassDoc currentClassDoc; + private final String constantsTableSummary; + + private final String[] constantsTableHeader; + /** * Construct a ConstantsSummaryWriter. * @param configuration the configuration used in this run @@ -59,6 +64,13 @@ public class ConstantsSummaryWriterImpl extends HtmlDocletWriter throws IOException { super(configuration, ConfigurationImpl.CONSTANTS_FILE_NAME); this.configuration = configuration; + constantsTableSummary = configuration.getText("doclet.Constants_Table_Summary", + configuration.getText("doclet.Constants_Summary")); + constantsTableHeader = new String[] { + getModifierTypeHeader(), + configuration.getText("doclet.ConstantField"), + configuration.getText("doclet.Value") + }; } /** @@ -151,12 +163,11 @@ public class ConstantsSummaryWriterImpl extends HtmlDocletWriter * @param classStr the heading to print. */ protected void writeClassName(String classStr) { - table(1, 3, 0); - trBgcolorStyle("#EEEEFF", "TableSubHeadingColor"); - thAlignColspan("left", 3); + table(1, 3, 0, constantsTableSummary); + tableSubCaptionStart(); write(classStr); - thEnd(); - trEnd(); + tableCaptionEnd(); + summaryTableHeader(constantsTableHeader, "col"); } private void tableFooter(boolean isHeader) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstructorWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstructorWriterImpl.java index cb5adbdeeaf..cc38edd8f2c 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstructorWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstructorWriterImpl.java @@ -37,6 +37,7 @@ import com.sun.tools.doclets.internal.toolkit.util.*; * * @author Robert Field * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) */ public class ConstructorWriterImpl extends AbstractExecutableMemberWriter implements ConstructorWriter, MemberSummaryWriter { @@ -211,8 +212,34 @@ public class ConstructorWriterImpl extends AbstractExecutableMemberWriter this.foundNonPubConstructor = foundNonPubConstructor; } - public void printSummaryLabel(ClassDoc cd) { - writer.strongText("doclet.Constructor_Summary"); + public void printSummaryLabel() { + writer.printText("doclet.Constructor_Summary"); + } + + public void printTableSummary() { + writer.tableIndexSummary(configuration().getText("doclet.Member_Table_Summary", + configuration().getText("doclet.Constructor_Summary"), + configuration().getText("doclet.constructors"))); + } + + public void printSummaryTableHeader(ProgramElementDoc member) { + String[] header; + if (foundNonPubConstructor) { + header = new String[] { + configuration().getText("doclet.Modifier"), + configuration().getText("doclet.0_and_1", + configuration().getText("doclet.Constructor"), + configuration().getText("doclet.Description")) + }; + } + else { + header = new String[] { + configuration().getText("doclet.0_and_1", + configuration().getText("doclet.Constructor"), + configuration().getText("doclet.Description")) + }; + } + writer.summaryTableHeader(header, "col"); } public void printSummaryAnchor(ClassDoc cd) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/DeprecatedListWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/DeprecatedListWriter.java index 68b04a7d72a..46c257b4b47 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/DeprecatedListWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/DeprecatedListWriter.java @@ -35,6 +35,7 @@ import java.io.*; * * @see java.util.List * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) */ public class DeprecatedListWriter extends SubWriterHolderWriter { @@ -55,6 +56,28 @@ public class DeprecatedListWriter extends SubWriterHolderWriter { "doclet.Deprecated_Annotation_Type_Members" }; + private static final String[] SUMMARY_KEYS = new String[] { + "doclet.deprecated_interfaces", "doclet.deprecated_classes", + "doclet.deprecated_enums", "doclet.deprecated_exceptions", + "doclet.deprecated_errors", + "doclet.deprecated_annotation_types", + "doclet.deprecated_fields", + "doclet.deprecated_methods", "doclet.deprecated_constructors", + "doclet.deprecated_enum_constants", + "doclet.deprecated_annotation_type_members" + }; + + private static final String[] HEADER_KEYS = new String[] { + "doclet.Interface", "doclet.Class", + "doclet.Enum", "doclet.Exceptions", + "doclet.Errors", + "doclet.AnnotationType", + "doclet.Field", + "doclet.Method", "doclet.Constructor", + "doclet.Enum_Constant", + "doclet.Annotation_Type_Member" + }; + private AbstractMemberWriter[] writers; private ConfigurationImpl configuration; @@ -119,11 +142,20 @@ public class DeprecatedListWriter extends SubWriterHolderWriter { ulEnd(); println(); + String memberTableSummary; + String[] memberTableHeader = new String[1]; for (int i = 0; i < DeprecatedAPIListBuilder.NUM_TYPES; i++) { if (deprapi.hasDocumentation(i)) { writeAnchor(deprapi, i); + memberTableSummary = + configuration.getText("doclet.Member_Table_Summary", + configuration.getText(HEADING_KEYS[i]), + configuration.getText(SUMMARY_KEYS[i])); + memberTableHeader[0] = configuration.getText("doclet.0_and_1", + configuration.getText(HEADER_KEYS[i]), + configuration.getText("doclet.Description")); writers[i].printDeprecatedAPI(deprapi.getList(i), - HEADING_KEYS[i]); + HEADING_KEYS[i], memberTableSummary, memberTableHeader); } } printDeprecatedFooter(); diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/EnumConstantWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/EnumConstantWriterImpl.java index 1d5b4ffbd29..2e7c08bcfb5 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/EnumConstantWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/EnumConstantWriterImpl.java @@ -35,6 +35,7 @@ import com.sun.tools.doclets.internal.toolkit.util.*; * Writes enum constant documentation in HTML format. * * @author Jamie Ho + * @author Bhavesh Patel (Modified) */ public class EnumConstantWriterImpl extends AbstractMemberWriter implements EnumConstantWriter, MemberSummaryWriter { @@ -194,8 +195,23 @@ public class EnumConstantWriterImpl extends AbstractMemberWriter return VisibleMemberMap.ENUM_CONSTANTS; } - public void printSummaryLabel(ClassDoc cd) { - writer.strongText("doclet.Enum_Constant_Summary"); + public void printSummaryLabel() { + writer.printText("doclet.Enum_Constant_Summary"); + } + + public void printTableSummary() { + writer.tableIndexSummary(configuration().getText("doclet.Member_Table_Summary", + configuration().getText("doclet.Enum_Constant_Summary"), + configuration().getText("doclet.enum_constants"))); + } + + public void printSummaryTableHeader(ProgramElementDoc member) { + String[] header = new String[] { + configuration().getText("doclet.0_and_1", + configuration().getText("doclet.Enum_Constant"), + configuration().getText("doclet.Description")) + }; + writer.summaryTableHeader(header, "col"); } public void printSummaryAnchor(ClassDoc cd) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/FieldWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/FieldWriterImpl.java index bd97166b8ab..0f3b1cc0ef3 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/FieldWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/FieldWriterImpl.java @@ -37,6 +37,7 @@ import com.sun.tools.doclets.internal.toolkit.util.*; * @author Robert Field * @author Atul M Dambalkar * @author Jamie Ho (rewrite) + * @author Bhavesh Patel (Modified) */ public class FieldWriterImpl extends AbstractMemberWriter implements FieldWriter, MemberSummaryWriter { @@ -236,8 +237,24 @@ public class FieldWriterImpl extends AbstractMemberWriter return VisibleMemberMap.FIELDS; } - public void printSummaryLabel(ClassDoc cd) { - writer.strongText("doclet.Field_Summary"); + public void printSummaryLabel() { + writer.printText("doclet.Field_Summary"); + } + + public void printTableSummary() { + writer.tableIndexSummary(configuration().getText("doclet.Member_Table_Summary", + configuration().getText("doclet.Field_Summary"), + configuration().getText("doclet.fields"))); + } + + public void printSummaryTableHeader(ProgramElementDoc member) { + String[] header = new String[] { + writer.getModifierTypeHeader(), + configuration().getText("doclet.0_and_1", + configuration().getText("doclet.Field"), + configuration().getText("doclet.Description")) + }; + writer.summaryTableHeader(header, "col"); } public void printSummaryAnchor(ClassDoc cd) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java index 689661b2e54..74d287dd79b 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java @@ -784,6 +784,15 @@ public class HtmlDocletWriter extends HtmlDocWriter { table(1, "100%", 3, 0); } + /** + * Print the Html table tag for the index summary tables. + * + * @param summary the summary for the table tag summary attribute. + */ + public void tableIndexSummary(String summary) { + table(1, "100%", 3, 0, summary); + } + /** * Same as {@link #tableIndexSummary()}. */ @@ -799,6 +808,40 @@ public class HtmlDocletWriter extends HtmlDocWriter { print(""); } + /** + * Print table caption. + */ + public void tableCaptionStart() { + captionStyle("TableCaption"); + } + + /** + * Print table sub-caption. + */ + public void tableSubCaptionStart() { + captionStyle("TableSubCaption"); + } + + /** + * Print table caption end tags. + */ + public void tableCaptionEnd() { + captionEnd(); + } + + /** + * Print summary table header. + */ + public void summaryTableHeader(String[] header, String scope) { + tr(); + for ( int i=0; i < header.length; i++ ) { + thScopeNoWrap("TableHeader", scope); + print(header[i]); + thEnd(); + } + trEnd(); + } + /** * Prine table header information about color, column span and the font. * diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/MethodWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/MethodWriterImpl.java index a74283179b3..c5500a34e4c 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/MethodWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/MethodWriterImpl.java @@ -38,6 +38,7 @@ import com.sun.tools.doclets.internal.toolkit.taglets.*; * @author Robert Field * @author Atul M Dambalkar * @author Jamie Ho (rewrite) + * @author Bhavesh Patel (Modified) */ public class MethodWriterImpl extends AbstractExecutableMemberWriter implements MethodWriter, MemberSummaryWriter { @@ -255,8 +256,24 @@ public class MethodWriterImpl extends AbstractExecutableMemberWriter return VisibleMemberMap.METHODS; } - public void printSummaryLabel(ClassDoc cd) { - writer.strongText("doclet.Method_Summary"); + public void printSummaryLabel() { + writer.printText("doclet.Method_Summary"); + } + + public void printTableSummary() { + writer.tableIndexSummary(configuration().getText("doclet.Member_Table_Summary", + configuration().getText("doclet.Method_Summary"), + configuration().getText("doclet.methods"))); + } + + public void printSummaryTableHeader(ProgramElementDoc member) { + String[] header = new String[] { + writer.getModifierTypeHeader(), + configuration().getText("doclet.0_and_1", + configuration().getText("doclet.Method"), + configuration().getText("doclet.Description")) + }; + writer.summaryTableHeader(header, "col"); } public void printSummaryAnchor(ClassDoc cd) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/NestedClassWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/NestedClassWriterImpl.java index 23803455ad1..c133708c108 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/NestedClassWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/NestedClassWriterImpl.java @@ -37,6 +37,7 @@ import com.sun.tools.doclets.internal.toolkit.util.*; * @author Robert Field * @author Atul M Dambalkar * @author Jamie Ho (rewrite) + * @author Bhavesh Patel (Modified) */ public class NestedClassWriterImpl extends AbstractMemberWriter implements MemberSummaryWriter { @@ -147,8 +148,35 @@ public class NestedClassWriterImpl extends AbstractMemberWriter return VisibleMemberMap.INNERCLASSES; } - public void printSummaryLabel(ClassDoc cd) { - writer.strongText("doclet.Nested_Class_Summary"); + public void printSummaryLabel() { + writer.printText("doclet.Nested_Class_Summary"); + } + + public void printTableSummary() { + writer.tableIndexSummary(configuration().getText("doclet.Member_Table_Summary", + configuration().getText("doclet.Nested_Class_Summary"), + configuration().getText("doclet.nested_classes"))); + } + + public void printSummaryTableHeader(ProgramElementDoc member) { + String[] header; + if (member.isInterface()) { + header = new String[] { + writer.getModifierTypeHeader(), + configuration().getText("doclet.0_and_1", + configuration().getText("doclet.Interface"), + configuration().getText("doclet.Description")) + }; + } + else { + header = new String[] { + writer.getModifierTypeHeader(), + configuration().getText("doclet.0_and_1", + configuration().getText("doclet.Class"), + configuration().getText("doclet.Description")) + }; + } + writer.summaryTableHeader(header, "col"); } public void printSummaryAnchor(ClassDoc cd) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexFrameWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexFrameWriter.java index ebc7118ab5d..035c48cfa80 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexFrameWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexFrameWriter.java @@ -114,7 +114,7 @@ public class PackageIndexFrameWriter extends AbstractPackageIndexWriter { * * @param text Text string will not be used in this method. */ - protected void printIndexHeader(String text) { + protected void printIndexHeader(String text, String tableSummary) { printTableHeader(false); } diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexWriter.java index 4562e6e9354..b785bf67c42 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexWriter.java @@ -36,6 +36,7 @@ import java.util.*; * with the "pacakge-summary.html" file for the clicked package. * * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) */ public class PackageIndexWriter extends AbstractPackageIndexWriter { @@ -123,7 +124,10 @@ public class PackageIndexWriter extends AbstractPackageIndexWriter { List list = groupPackageMap.get(groupname); if (list != null && list.size() > 0) { printIndexContents(list.toArray(new PackageDoc[list.size()]), - groupname); + groupname, + configuration.getText("doclet.Member_Table_Summary", + groupname, + configuration.getText("doclet.packages"))); } } } @@ -149,11 +153,12 @@ public class PackageIndexWriter extends AbstractPackageIndexWriter { /** * Print Html tags for the table for this package index. */ - protected void printIndexHeader(String text) { - tableIndexSummary(); - tableHeaderStart("#CCCCFF"); - strong(text); - tableHeaderEnd(); + protected void printIndexHeader(String text, String tableSummary) { + tableIndexSummary(tableSummary); + tableCaptionStart(); + print(text); + tableCaptionEnd(); + summaryTableHeader(packageTableHeader, "col"); } /** diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageUseWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageUseWriter.java index a83cc3d70a0..d817ca5ad3b 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageUseWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageUseWriter.java @@ -34,6 +34,7 @@ import java.util.*; * Generate package usage information. * * @author Robert G. Field + * @author Bhavesh Patel (Modified) */ public class PackageUseWriter extends SubWriterHolderWriter { @@ -131,11 +132,12 @@ public class PackageUseWriter extends SubWriterHolderWriter { } protected void generatePackageList() throws IOException { - tableIndexSummary(); - tableHeaderStart("#CCCCFF"); + tableIndexSummary(useTableSummary); + tableCaptionStart(); printText("doclet.ClassUse_Packages.that.use.0", getPackageLink(pkgdoc, Util.getPackageName(pkgdoc), false)); - tableHeaderEnd(); + tableCaptionEnd(); + summaryTableHeader(packageTableHeader, "col"); Iterator it = usingPackageToUsedClasses.keySet().iterator(); while (it.hasNext()) { PackageDoc pkg = configuration.root.packageNamed(it.next()); @@ -147,6 +149,11 @@ public class PackageUseWriter extends SubWriterHolderWriter { } protected void generateClassList() throws IOException { + String[] classTableHeader = new String[] { + configuration.getText("doclet.0_and_1", + configuration.getText("doclet.Class"), + configuration.getText("doclet.Description")) + }; Iterator itp = usingPackageToUsedClasses.keySet().iterator(); while (itp.hasNext()) { String packageName = itp.next(); @@ -154,12 +161,14 @@ public class PackageUseWriter extends SubWriterHolderWriter { if (usingPackage != null) { anchor(usingPackage.name()); } - tableIndexSummary(); - tableHeaderStart("#CCCCFF"); + tableIndexSummary(configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.classes"))); + tableCaptionStart(); printText("doclet.ClassUse_Classes.in.0.used.by.1", getPackageLink(pkgdoc, Util.getPackageName(pkgdoc), false), getPackageLink(usingPackage,Util.getPackageName(usingPackage), false)); - tableHeaderEnd(); + tableCaptionEnd(); + summaryTableHeader(classTableHeader, "col"); Iterator itc = usingPackageToUsedClasses.get(packageName).iterator(); while (itc.hasNext()) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageWriterImpl.java index eca6d49bbbf..60aa692ce0f 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageWriterImpl.java @@ -38,6 +38,7 @@ import java.util.*; * class-kind will update the frame with the clicked class-kind page. * * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) */ public class PackageWriterImpl extends HtmlDocletWriter implements PackageSummaryWriter { @@ -107,14 +108,15 @@ public class PackageWriterImpl extends HtmlDocletWriter /** * {@inheritDoc} */ - public void writeClassesSummary(ClassDoc[] classes, String label) { + public void writeClassesSummary(ClassDoc[] classes, String label, String tableSummary, String[] tableHeader) { if(classes.length > 0) { Arrays.sort(classes); - tableIndexSummary(); + tableIndexSummary(tableSummary); boolean printedHeading = false; for (int i = 0; i < classes.length; i++) { if (!printedHeading) { - printFirstRow(label); + printTableCaption(label); + printFirstRow(tableHeader); printedHeading = true; } if (!Util.isCoreClass(classes[i]) || @@ -148,15 +150,24 @@ public class PackageWriterImpl extends HtmlDocletWriter } } + /** + * Print the table caption for the class-listing. + * + * @param label label for the Class kind listing. + */ + protected void printTableCaption(String label) { + tableCaptionStart(); + print(label); + tableCaptionEnd(); + } + /** * Print the table heading for the class-listing. * - * @param label Label for the Class kind listing. + * @param tableHeader table header string for the Class listing. */ - protected void printFirstRow(String label) { - tableHeaderStart("#CCCCFF"); - strong(label); - tableHeaderEnd(); + protected void printFirstRow(String[] tableHeader) { + summaryTableHeader(tableHeader, "col"); } /** diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/StylesheetWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/StylesheetWriter.java index 1384bbb2bd5..f6664f94c1c 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/StylesheetWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/StylesheetWriter.java @@ -33,6 +33,7 @@ import java.io.*; * Writes the style sheet for the doclet output. * * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) */ public class StylesheetWriter extends HtmlDocletWriter { @@ -115,6 +116,13 @@ public class StylesheetWriter extends HtmlDocletWriter { println("background-color:#FFFFFF; color:#000000}"); print(".NavBarCell3 { font-family: Arial, Helvetica, sans-serif; "); println("background-color:#FFFFFF; color:#000000}"); + + print("/* "); printText("doclet.Style_line_12"); println(" */"); + print(".TableCaption { background: #CCCCFF; color:#000000; text-align: left; font-size: 150%; font-weight: bold; border-left: 2px ridge; border-right: 2px ridge; border-top: 2px ridge; padding-left: 5px; }"); + print(" /* "); printText("doclet.Style_line_5"); println(" */"); + print(".TableSubCaption { background: #EEEEFF; color:#000000; text-align: left; font-weight: bold; border-left: 2px ridge; border-right: 2px ridge; border-top: 2px ridge; padding-left: 5px; }"); + print(" /* "); printText("doclet.Style_line_6"); println(" */"); + print(".TableHeader { text-align: center; font-size: 80%; font-weight: bold; }"); println(""); } diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/SubWriterHolderWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/SubWriterHolderWriter.java index f6b6b98b6e5..b1a2f868687 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/SubWriterHolderWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/SubWriterHolderWriter.java @@ -43,6 +43,7 @@ import java.io.*; * * @author Robert Field * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) */ public abstract class SubWriterHolderWriter extends HtmlDocletWriter { @@ -72,10 +73,11 @@ public abstract class SubWriterHolderWriter extends HtmlDocletWriter { public void printSummaryHeader(AbstractMemberWriter mw, ClassDoc cd) { mw.printSummaryAnchor(cd); - tableIndexSummary(); - tableHeaderStart("#CCCCFF"); - mw.printSummaryLabel(cd); - tableHeaderEnd(); + mw.printTableSummary(); + tableCaptionStart(); + mw.printSummaryLabel(); + tableCaptionEnd(); + mw.printSummaryTableHeader(cd); } public void printTableHeadingBackground(String str) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlWriter.java index 4df4f5d6a0e..cad683d9fa4 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlWriter.java @@ -37,6 +37,7 @@ import com.sun.tools.doclets.internal.toolkit.util.*; * * @since 1.2 * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) */ public class HtmlWriter extends PrintWriter { @@ -66,6 +67,21 @@ public class HtmlWriter extends PrintWriter { */ protected boolean memberDetailsListPrinted; + /** + * Header for tables displaying packages and description.. + */ + protected final String[] packageTableHeader; + + /** + * Summary for use tables displaying class and package use. + */ + protected final String useTableSummary; + + /** + * Column header for class docs displaying Modifier and Type header. + */ + protected final String modifierTypeHeader; + /** * Constructor. * @@ -86,6 +102,15 @@ public class HtmlWriter extends PrintWriter { this.configuration = configuration; htmlFilename = filename; this.memberDetailsListPrinted = false; + packageTableHeader = new String[] { + configuration.getText("doclet.Package"), + configuration.getText("doclet.Description") + }; + useTableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.packages")); + modifierTypeHeader = configuration.getText("doclet.0_and_1", + configuration.getText("doclet.Modifier"), + configuration.getText("doclet.Type")); } /** @@ -802,6 +827,26 @@ public class HtmlWriter extends PrintWriter { "\" SUMMARY=\"\">"); } + /** + * Print HTML <TABLE BORDER="border" WIDTH="width" + * CELLPADDING="cellpadding" CELLSPACING="cellspacing" SUMMARY="summary"> tag. + * + * @param border Border size. + * @param width Width of the table. + * @param cellpadding Cellpadding for the table cells. + * @param cellspacing Cellspacing for the table cells. + * @param summary Table summary. + */ + public void table(int border, String width, int cellpadding, + int cellspacing, String summary) { + println(DocletConstants.NL + + ""); + } + /** * Print HTML <TABLE BORDER="border" CELLPADDING="cellpadding" * CELLSPACING="cellspacing"> tag. @@ -818,6 +863,23 @@ public class HtmlWriter extends PrintWriter { "\" SUMMARY=\"\">"); } + /** + * Print HTML <TABLE BORDER="border" CELLPADDING="cellpadding" + * CELLSPACING="cellspacing" SUMMARY="summary"> tag. + * + * @param border Border size. + * @param cellpadding Cellpadding for the table cells. + * @param cellspacing Cellspacing for the table cells. + * @param summary Table summary. + */ + public void table(int border, int cellpadding, int cellspacing, String summary) { + println(DocletConstants.NL + + "
"); + } + /** * Print HTML <TABLE BORDER="border" WIDTH="width"> * @@ -912,6 +974,23 @@ public class HtmlWriter extends PrintWriter { println("-->"); } + /** + * Print <CAPTION CLASS="stylename"> tag. Adds a newline character + * at the end. + * + * @param stylename style to be applied. + */ + public void captionStyle(String stylename) { + println(""); + } + /** * Print <TR BGCOLOR="color" CLASS="stylename"> tag. Adds a newline character * at the end. @@ -952,6 +1031,23 @@ public class HtmlWriter extends PrintWriter { print("" + "" + NL + "" }, // Class documentation {BUG_ID + FS + "pkg1" + FS + "C1.html", - "" + "" + NL + "" }, {BUG_ID + FS + "pkg1" + FS + "C1.html", "" @@ -62,29 +64,32 @@ public class TestHeadings extends JavadocTester { // Class use documentation {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "C1.html", - "" + "" + NL + "" }, {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "C1.html", "" }, {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "C1.html", - "" + "" + NL + "" }, // Deprecated {BUG_ID + FS + "deprecated-list.html", - "" + "" }, // Constant values {BUG_ID + FS + "constant-values.html", - "" - }, - {BUG_ID + FS + "constant-values.html", - "" + "" + NL + "" + NL + + "" }, // Serialized Form diff --git a/langtools/test/com/sun/javadoc/testHtmlStrongTag/TestHtmlStrongTag.java b/langtools/test/com/sun/javadoc/testHtmlStrongTag/TestHtmlStrongTag.java index 3bb26e83992..c1445255c42 100644 --- a/langtools/test/com/sun/javadoc/testHtmlStrongTag/TestHtmlStrongTag.java +++ b/langtools/test/com/sun/javadoc/testHtmlStrongTag/TestHtmlStrongTag.java @@ -38,14 +38,15 @@ public class TestHtmlStrongTag extends JavadocTester { private static final String BUG_ID = "6786028"; private static final String[][] TEST1 = { - {BUG_ID + FS + "pkg1" + FS + "C1.html", "Method Summary"}, - {BUG_ID + FS + "pkg1" + FS + "C1.html", "See Also:"}, - {BUG_ID + FS + "pkg1" + FS + "package-summary.html", "Class Summary"}}; + {BUG_ID + FS + "pkg1" + FS + "C1.html", "See Also:"}}; private static final String[][] NEGATED_TEST1 = { - {BUG_ID + FS + "pkg1" + FS + "C1.html", ""}}; + {BUG_ID + FS + "pkg1" + FS + "C1.html", "Method Summary"}, + {BUG_ID + FS + "pkg1" + FS + "C1.html", ""}, + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", "Class Summary"}}; private static final String[][] TEST2 = { + {BUG_ID + FS + "pkg2" + FS + "C2.html", "Comments:"}}; + private static final String[][] NEGATED_TEST2 = { {BUG_ID + FS + "pkg2" + FS + "C2.html", "Method Summary"}, - {BUG_ID + FS + "pkg2" + FS + "C2.html", "Comments:"}, {BUG_ID + FS + "pkg1" + FS + "package-summary.html", "Class Summary"}}; private static final String[] ARGS1 = @@ -62,7 +63,7 @@ public class TestHtmlStrongTag extends JavadocTester { public static void main(String[] args) { TestHtmlStrongTag tester = new TestHtmlStrongTag(); run(tester, ARGS1, TEST1, NEGATED_TEST1); - run(tester, ARGS2, TEST2, NO_TEST); + run(tester, ARGS2, TEST2, NEGATED_TEST2); tester.printSummary(); } diff --git a/langtools/test/com/sun/javadoc/testHtmlTableTags/TestHtmlTableTags.java b/langtools/test/com/sun/javadoc/testHtmlTableTags/TestHtmlTableTags.java new file mode 100644 index 00000000000..f08ff5783d1 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlTableTags/TestHtmlTableTags.java @@ -0,0 +1,478 @@ +/* + * 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 6786688 + * @summary HTML tables should have table summary, caption and table headers. + * @author Bhavesh Patel + * @library ../lib/ + * @build JavadocTester + * @build TestHtmlTableTags + * @run main TestHtmlTableTags + */ + +public class TestHtmlTableTags extends JavadocTester { + + //Test information. + private static final String BUG_ID = "6786688"; + + //Javadoc arguments. + private static final String[] ARGS = new String[] { + "-d", BUG_ID, "-sourcepath", SRC_DIR, "-use", "pkg1", "pkg2" + }; + + //Input for string tests for HTML table tags. + private static final String[][] TABLE_TAGS_TEST = { + /* + * Test for validating summary for HTML tables + */ + + //Package summary + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", + "
"); + } + + /** + * Print </CAPTION> tag. Add a newline character at the end. + */ + public void captionEnd() { + println("
"); } + /** + * Print <TH CLASS="stylename" SCOPE="scope" NOWRAP> tag. + * + * @param stylename style to be applied. + * @param scope the scope attribute. + */ + public void thScopeNoWrap(String stylename, String scope) { + print(""); + } + + /* + * Returns a header for Modifier and Type column of a table. + */ + public String getModifierTypeHeader() { + return modifierTypeHeader; + } + /** * Print <TH align="align" COLSPAN=i> tag. * diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties index 492a77e7fcc..f4d86e3d5d8 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties @@ -83,6 +83,17 @@ doclet.Deprecated_Constructors=Deprecated Constructors doclet.Deprecated_Methods=Deprecated Methods doclet.Deprecated_Enum_Constants=Deprecated Enum Constants doclet.Deprecated_Annotation_Type_Members=Deprecated Annotation Type Elements +doclet.deprecated_classes=deprecated classes +doclet.deprecated_enums=deprecated enums +doclet.deprecated_interfaces=deprecated interfaces +doclet.deprecated_exceptions=deprecated exceptions +doclet.deprecated_annotation_types=deprecated annotation types +doclet.deprecated_errors=deprecated errors +doclet.deprecated_fields=deprecated fields +doclet.deprecated_constructors=deprecated constructors +doclet.deprecated_methods=deprecated methods +doclet.deprecated_enum_constants=deprecated enum constants +doclet.deprecated_annotation_type_members=deprecated annotation type elements doclet.Frame_Output=Frame Output doclet.Docs_generated_by_Javadoc=Documentation generated by Javadoc. doclet.Generated_Docs_Untitled=Generated Documentation (Untitled) @@ -171,6 +182,7 @@ doclet.Style_line_8=Font used in left-hand frame lists doclet.Style_line_9=Example of smaller, sans-serif font in frames doclet.Style_line_10=Navigation bar fonts and colors doclet.Style_line_11=Dark Blue +doclet.Style_line_12=Table caption style doclet.ClassUse_Packages.that.use.0=Packages that use {0} doclet.ClassUse_Uses.of.0.in.1=Uses of {0} in {1} doclet.ClassUse_Classes.in.0.used.by.1=Classes in {0} used by {1} diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/PackageSummaryWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/PackageSummaryWriter.java index eb86fbea2d9..d46807d02e4 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/PackageSummaryWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/PackageSummaryWriter.java @@ -64,7 +64,7 @@ public interface PackageSummaryWriter { * @param classes the array of classes to document. * @param label the label for this table. */ - public abstract void writeClassesSummary(ClassDoc[] classes, String label); + public abstract void writeClassesSummary(ClassDoc[] classes, String label, String tableSummary, String[] tableHeader); /** * Write the header for the summary. diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/PackageSummaryBuilder.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/PackageSummaryBuilder.java index c85b0b30b8d..ac25c257739 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/PackageSummaryBuilder.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/PackageSummaryBuilder.java @@ -40,6 +40,7 @@ import java.lang.reflect.*; * Do not use it as an API * * @author Jamie Ho + * @author Bhavesh Patel (Modified) * @since 1.5 */ public class PackageSummaryBuilder extends AbstractBuilder { @@ -184,7 +185,15 @@ public class PackageSummaryBuilder extends AbstractBuilder { * Build the summary for the classes in this package. */ public void buildClassSummary() { - ClassDoc[] classes = + String classTableSummary = + configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Class_Summary"), + configuration.getText("doclet.classes")); + String[] classTableHeader = new String[] { + configuration.getText("doclet.Class"), + configuration.getText("doclet.Description") + }; + ClassDoc[] classes = packageDoc.isIncluded() ? packageDoc.ordinaryClasses() : configuration.classDocCatalog.ordinaryClasses( @@ -192,7 +201,8 @@ public class PackageSummaryBuilder extends AbstractBuilder { if (classes.length > 0) { packageWriter.writeClassesSummary( classes, - configuration.getText("doclet.Class_Summary")); + configuration.getText("doclet.Class_Summary"), + classTableSummary, classTableHeader); } } @@ -200,7 +210,15 @@ public class PackageSummaryBuilder extends AbstractBuilder { * Build the summary for the interfaces in this package. */ public void buildInterfaceSummary() { - ClassDoc[] interfaces = + String interfaceTableSummary = + configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Interface_Summary"), + configuration.getText("doclet.interfaces")); + String[] interfaceTableHeader = new String[] { + configuration.getText("doclet.Interface"), + configuration.getText("doclet.Description") + }; + ClassDoc[] interfaces = packageDoc.isIncluded() ? packageDoc.interfaces() : configuration.classDocCatalog.interfaces( @@ -208,7 +226,8 @@ public class PackageSummaryBuilder extends AbstractBuilder { if (interfaces.length > 0) { packageWriter.writeClassesSummary( interfaces, - configuration.getText("doclet.Interface_Summary")); + configuration.getText("doclet.Interface_Summary"), + interfaceTableSummary, interfaceTableHeader); } } @@ -216,7 +235,15 @@ public class PackageSummaryBuilder extends AbstractBuilder { * Build the summary for the enums in this package. */ public void buildAnnotationTypeSummary() { - ClassDoc[] annotationTypes = + String annotationtypeTableSummary = + configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Annotation_Types_Summary"), + configuration.getText("doclet.annotationtypes")); + String[] annotationtypeTableHeader = new String[] { + configuration.getText("doclet.AnnotationType"), + configuration.getText("doclet.Description") + }; + ClassDoc[] annotationTypes = packageDoc.isIncluded() ? packageDoc.annotationTypes() : configuration.classDocCatalog.annotationTypes( @@ -224,7 +251,8 @@ public class PackageSummaryBuilder extends AbstractBuilder { if (annotationTypes.length > 0) { packageWriter.writeClassesSummary( annotationTypes, - configuration.getText("doclet.Annotation_Types_Summary")); + configuration.getText("doclet.Annotation_Types_Summary"), + annotationtypeTableSummary, annotationtypeTableHeader); } } @@ -232,7 +260,15 @@ public class PackageSummaryBuilder extends AbstractBuilder { * Build the summary for the enums in this package. */ public void buildEnumSummary() { - ClassDoc[] enums = + String enumTableSummary = + configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Enum_Summary"), + configuration.getText("doclet.enums")); + String[] enumTableHeader = new String[] { + configuration.getText("doclet.Enum"), + configuration.getText("doclet.Description") + }; + ClassDoc[] enums = packageDoc.isIncluded() ? packageDoc.enums() : configuration.classDocCatalog.enums( @@ -240,7 +276,8 @@ public class PackageSummaryBuilder extends AbstractBuilder { if (enums.length > 0) { packageWriter.writeClassesSummary( enums, - configuration.getText("doclet.Enum_Summary")); + configuration.getText("doclet.Enum_Summary"), + enumTableSummary, enumTableHeader); } } @@ -248,7 +285,15 @@ public class PackageSummaryBuilder extends AbstractBuilder { * Build the summary for the exceptions in this package. */ public void buildExceptionSummary() { - ClassDoc[] exceptions = + String exceptionTableSummary = + configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Exception_Summary"), + configuration.getText("doclet.exceptions")); + String[] exceptionTableHeader = new String[] { + configuration.getText("doclet.Exception"), + configuration.getText("doclet.Description") + }; + ClassDoc[] exceptions = packageDoc.isIncluded() ? packageDoc.exceptions() : configuration.classDocCatalog.exceptions( @@ -256,7 +301,8 @@ public class PackageSummaryBuilder extends AbstractBuilder { if (exceptions.length > 0) { packageWriter.writeClassesSummary( exceptions, - configuration.getText("doclet.Exception_Summary")); + configuration.getText("doclet.Exception_Summary"), + exceptionTableSummary, exceptionTableHeader); } } @@ -264,7 +310,15 @@ public class PackageSummaryBuilder extends AbstractBuilder { * Build the summary for the errors in this package. */ public void buildErrorSummary() { - ClassDoc[] errors = + String errorTableSummary = + configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Error_Summary"), + configuration.getText("doclet.errors")); + String[] errorTableHeader = new String[] { + configuration.getText("doclet.Error"), + configuration.getText("doclet.Description") + }; + ClassDoc[] errors = packageDoc.isIncluded() ? packageDoc.errors() : configuration.classDocCatalog.errors( @@ -272,7 +326,8 @@ public class PackageSummaryBuilder extends AbstractBuilder { if (errors.length > 0) { packageWriter.writeClassesSummary( errors, - configuration.getText("doclet.Error_Summary")); + configuration.getText("doclet.Error_Summary"), + errorTableSummary, errorTableHeader); } } diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclets.properties b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclets.properties index 57382de9ab2..371bdf596f1 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclets.properties +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclets.properties @@ -82,6 +82,7 @@ doclet.Exceptions=Exceptions doclet.Errors=Errors doclet.Classes=Classes doclet.Packages=Packages +doclet.packages=packages doclet.All_Classes=All Classes doclet.All_Superinterfaces=All Superinterfaces: doclet.All_Implemented_Interfaces=All Implemented Interfaces: @@ -92,14 +93,20 @@ doclet.Interface=Interface doclet.Class=Class doclet.AnnotationType=Annotation Type doclet.annotationtype=annotation type +doclet.annotationtypes=annotation types doclet.Enum=Enum doclet.enum=enum +doclet.enums=enums doclet.interface=interface +doclet.interfaces=interfaces doclet.class=class +doclet.classes=classes doclet.Error=Error doclet.error=error +doclet.errors=errors doclet.Exception=Exception doclet.exception=exception +doclet.exceptions=exceptions doclet.extended_by=extended by doclet.extends=extends doclet.Package_private=(package private) @@ -125,6 +132,32 @@ doclet.value_tag_invalid_reference={0} (referenced by @value tag) is an unknown doclet.value_tag_invalid_constant=@value tag (which references {0}) can only be used in constants. doclet.dest_dir_create=Creating destination directory: "{0}" doclet.in={0} in {1} +doclet.Use_Table_Summary=Use table, listing {0}, and an explanation +doclet.Constants_Table_Summary={0} table, listing constant fields, and values +doclet.Member_Table_Summary={0} table, listing {1}, and an explanation +doclet.fields=fields +doclet.constructors=constructors +doclet.methods=methods +doclet.annotation_type_optional_members=optional elements +doclet.annotation_type_required_members=required elements +doclet.enum_constants=enum constants +doclet.nested_classes=nested classes +doclet.subclasses=subclasses +doclet.subinterfaces=subinterfaces +doclet.Modifier=Modifier +doclet.Type=Type +doclet.Field=Field +doclet.Constructor=Constructor +doclet.Method=Method +doclet.Annotation_Type_Optional_Member=Optional Element +doclet.Annotation_Type_Required_Member=Required Element +doclet.Annotation_Type_Member=Annotation Type Element +doclet.Enum_Constant=Enum Constant +doclet.Class=Class +doclet.Description=Description +doclet.ConstantField=Constant Field +doclet.Value=Value +doclet.0_and_1={0} and {1} #Documentation for Enums doclet.enum_values_doc=\n\ diff --git a/langtools/test/com/sun/javadoc/testHeadings/TestHeadings.java b/langtools/test/com/sun/javadoc/testHeadings/TestHeadings.java index 1ed62c535db..eb82d715b91 100644 --- a/langtools/test/com/sun/javadoc/testHeadings/TestHeadings.java +++ b/langtools/test/com/sun/javadoc/testHeadings/TestHeadings.java @@ -47,14 +47,16 @@ public class TestHeadings extends JavadocTester { private static final String[][] TEST = { //Package summary {BUG_ID + FS + "pkg1" + FS + "package-summary.html", - "" + NL + - "Class Summary" + + "ClassDescription" + NL + - "Field Summary" + + "Modifier and TypeField and DescriptionMethods inherited from class " + "java.lang.Object" + NL + - "Packages that use C1" + + "PackageDescription" + NL + "Uses of C1 in " + "pkg2Fields in " + "pkg2 " + "declared as C1" + + "Modifier and TypeField and Description" + NL + - "Deprecated Methods" + + "Method and Descriptionpkg1.C1pkg1.C1" + + "Modifier and TypeConstant FieldValue
" + }, + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", + "
" + }, + {BUG_ID + FS + "pkg2" + FS + "package-summary.html", + "
" + }, + {BUG_ID + FS + "pkg2" + FS + "package-summary.html", + "
" + }, + // Class documentation + {BUG_ID + FS + "pkg1" + FS + "C1.html", + "
" + }, + {BUG_ID + FS + "pkg1" + FS + "C1.html", + "
" + }, + {BUG_ID + FS + "pkg2" + FS + "C2.html", + "
" + }, + {BUG_ID + FS + "pkg2" + FS + "C2.html", + "
" + }, + {BUG_ID + FS + "pkg2" + FS + "C2.ModalExclusionType.html", + "
" + }, + {BUG_ID + FS + "pkg2" + FS + "C3.html", + "
" + }, + {BUG_ID + FS + "pkg2" + FS + "C4.html", + "
" + }, + // Class use documentation + {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "I1.html", + "
" + }, + {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "C1.html", + "
" + }, + {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "C1.html", + "
" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.html", + "
" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.html", + "
" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.ModalExclusionType.html", + "
" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.ModalExclusionType.html", + "
" + }, + // Package use documentation + {BUG_ID + FS + "pkg1" + FS + "package-use.html", + "
" + }, + {BUG_ID + FS + "pkg1" + FS + "package-use.html", + "
" + }, + {BUG_ID + FS + "pkg2" + FS + "package-use.html", + "
" + }, + {BUG_ID + FS + "pkg2" + FS + "package-use.html", + "
" + }, + // Deprecated + {BUG_ID + FS + "deprecated-list.html", + "
" + }, + {BUG_ID + FS + "deprecated-list.html", + "
" + }, + // Constant values + {BUG_ID + FS + "constant-values.html", + "
" + }, + // Overview Summary + {BUG_ID + FS + "overview-summary.html", + "
" + }, + + /* + * Test for validating caption for HTML tables + */ + + //Package summary + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", + "" + }, + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "package-summary.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "package-summary.html", + "" + }, + // Class documentation + {BUG_ID + FS + "pkg1" + FS + "C1.html", + "" + }, + {BUG_ID + FS + "pkg1" + FS + "C1.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "C2.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "C2.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "C2.ModalExclusionType.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "C3.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "C4.html", + "" + }, + // Class use documentation + {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "I1.html", + "" + }, + {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "C1.html", + "" + }, + {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "C1.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.ModalExclusionType.html", + "" + }, + // Package use documentation + {BUG_ID + FS + "pkg1" + FS + "package-use.html", + "" + }, + {BUG_ID + FS + "pkg1" + FS + "package-use.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "package-use.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "package-use.html", + "" + }, + // Deprecated + {BUG_ID + FS + "deprecated-list.html", + "" + }, + {BUG_ID + FS + "deprecated-list.html", + "" + }, + // Constant values + {BUG_ID + FS + "constant-values.html", + "" + }, + // Overview Summary + {BUG_ID + FS + "overview-summary.html", + "" + }, + + /* + * Test for validating headers for HTML tables + */ + + //Package summary + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg2" + FS + "package-summary.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg2" + FS + "package-summary.html", + "" + NL + "" + }, + // Class documentation + {BUG_ID + FS + "pkg1" + FS + "C1.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg1" + FS + "C1.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg2" + FS + "C2.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg2" + FS + "C2.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "C2.ModalExclusionType.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "C3.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg2" + FS + "C4.html", + "" + NL + "" + }, + // Class use documentation + {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "I1.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "C1.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "C1.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.ModalExclusionType.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.ModalExclusionType.html", + "" + NL + "" + }, + // Package use documentation + {BUG_ID + FS + "pkg1" + FS + "package-use.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg1" + FS + "package-use.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "package-use.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg2" + FS + "package-use.html", + "" + }, + // Deprecated + {BUG_ID + FS + "deprecated-list.html", + "" + }, + {BUG_ID + FS + "deprecated-list.html", + "" + }, + // Constant values + {BUG_ID + FS + "constant-values.html", + "" + NL + "" + NL + + "" + }, + // Overview Summary + {BUG_ID + FS + "overview-summary.html", + "" + NL + "" + } + }; + private static final String[][] NEGATED_TEST = NO_TEST; + + /** + * The entry point of the test. + * @param args the array of command line arguments. + */ + public static void main(String[] args) { + TestHtmlTableTags tester = new TestHtmlTableTags(); + run(tester, ARGS, TABLE_TAGS_TEST, NEGATED_TEST); + tester.printSummary(); + } + + /** + * {@inheritDoc} + */ + public String getBugId() { + return BUG_ID; + } + + /** + * {@inheritDoc} + */ + public String getBugName() { + return getClass().getName(); + } +} diff --git a/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/C1.java b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/C1.java new file mode 100644 index 00000000000..5f38d4f1f29 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/C1.java @@ -0,0 +1,81 @@ +/* + * 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. + */ + +package pkg1; + +import pkg2.*; + +/** + * A test class. + * + * @author Bhavesh Patel + */ +public class C1 implements I1 { + + /** + * Test field for class. + */ + public C2 field; + + /** + * Constant value. + */ + public static final String CONSTANT1 = "C1"; + + /** + * A test constructor. + */ + C1() { + } + + /** + * Method thats does some processing. + * + * @param param some parameter that is passed. + * @return a sample object. + */ + public C2 method(C2 param) { + return param; + } + + /** + * Method that is implemented. + * + * @param a some random value. + * @param b some random value. + */ + public void method1(int a, int b) { + } + + /** + * Another inherited method. + * @param c some value. + */ + public void method2(int c) { + } + + /** + * @deprecated don't use this anymore. + */ + public void deprecatedMethod() {} +} diff --git a/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/I1.java b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/I1.java new file mode 100644 index 00000000000..509417825ac --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/I1.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package pkg1; + +/** + * A sample interface used to test table tags. + * + * @author Bhavesh Patel + */ +public interface I1 { + + /** + * A test method. + * + * @param a blah. + * @param b blah. + */ + void method1(int a, int b); + + /** + * Another test method. + * + * @param c blah. + */ + void method2(int c); + +} diff --git a/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/package-info.java b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/package-info.java new file mode 100644 index 00000000000..024483be5a7 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/package-info.java @@ -0,0 +1,27 @@ +/* + * 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 package 1 used to test table tags. + */ +package pkg1; diff --git a/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C2.java b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C2.java new file mode 100644 index 00000000000..07992e2bad1 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C2.java @@ -0,0 +1,73 @@ +/* + * 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. + */ + +package pkg2; + +import pkg1.*; + +/** + * Another test class. + * + * @author Bhavesh Patel + */ +public class C2 { + + /** + * A test field. + */ + public C1 field; + + /** + * @deprecated don't use this field anymore. + */ + public C1 dep_field; + + /** + * A sample enum. + */ + public static enum ModalExclusionType { + /** + * Test comment. + */ + NO_EXCLUDE, + /** + * Another comment. + */ + APPLICATION_EXCLUDE + }; + + /** + * A string constant. + */ + public static final String CONSTANT1 = "C2"; + + /** + * A sample method. + * + * @param param some parameter. + * @return a test object. + */ + public C1 method(C1 param) { + return param; + } +} diff --git a/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C3.java b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C3.java new file mode 100644 index 00000000000..e410266b6a5 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C3.java @@ -0,0 +1,40 @@ +/* + * 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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. + */ + +package pkg2; + +import java.lang.annotation.*; + +/** + * Test Annotation class. + * + * @author Bhavesh Patel + */ +public @interface C3 { + /** + * Comment. + */ + String[] value(); +} diff --git a/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C4.java b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C4.java new file mode 100644 index 00000000000..7eec427be53 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C4.java @@ -0,0 +1,35 @@ +/* + * 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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. + */ + +package pkg2; + +import java.lang.annotation.*; + +/* + * A sample interface. + */ +public @interface C4 { + boolean value() default true; +} diff --git a/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/package-info.java b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/package-info.java new file mode 100644 index 00000000000..a1523b14326 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/package-info.java @@ -0,0 +1,27 @@ +/* + * 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 package 2 used to test table tags. + */ +package pkg2; diff --git a/langtools/test/com/sun/javadoc/testNewLanguageFeatures/TestNewLanguageFeatures.java b/langtools/test/com/sun/javadoc/testNewLanguageFeatures/TestNewLanguageFeatures.java index 17eac18887a..5a5fb82b399 100644 --- a/langtools/test/com/sun/javadoc/testNewLanguageFeatures/TestNewLanguageFeatures.java +++ b/langtools/test/com/sun/javadoc/testNewLanguageFeatures/TestNewLanguageFeatures.java @@ -58,7 +58,8 @@ public class TestNewLanguageFeatures extends JavadocTester { "Coin>" }, //Check for enum constant section - {BUG_ID + FS + "pkg" + FS + "Coin.html", "Enum Constant Summary"}, + {BUG_ID + FS + "pkg" + FS + "Coin.html", ""}, //Detail for enum constant {BUG_ID + FS + "pkg" + FS + "Coin.html", "Dime"}, @@ -158,9 +159,11 @@ public class TestNewLanguageFeatures extends JavadocTester { "public @interface AnnotationType"}, //Make sure member summary headings are correct. {BUG_ID + FS + "pkg" + FS + "AnnotationType.html", - "Required Element Summary"}, + ""}, {BUG_ID + FS + "pkg" + FS + "AnnotationType.html", - "Optional Element Summary"}, + ""}, //Make sure element detail heading is correct {BUG_ID + FS + "pkg" + FS + "AnnotationType.html", "Element Detail"}, @@ -286,39 +289,57 @@ public class TestNewLanguageFeatures extends JavadocTester { //ClassUseTest1: {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo.html", - "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo.html", "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo.html", "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo.html", "ParamTest<Foo>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", - "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", "ParamTest<Foo>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo2.html", - "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo2.html", "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo2.html", "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", "ParamTest<Foo>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", - "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", "<T extends ParamTest<Foo3>>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo3.html", - "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo3.html", "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo3.html", "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo3.html", "<T extends ParamTest<Foo3>>" @@ -371,38 +414,61 @@ public class TestNewLanguageFeatures extends JavadocTester { //ClassUseTest3: >> {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest2.html", - "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest2.html", "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest2.html", "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest2.html", "<T extends ParamTest2<java.util.List<? extends Foo4>>>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo4.html", - "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo4.html", "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo4.html", "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo4.html", "<T extends ParamTest2<java.util.List<? extends Foo4>>>" @@ -410,81 +476,147 @@ public class TestNewLanguageFeatures extends JavadocTester { //Type parameters in constructor and method args {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo4.html", - "" + NL + - "" + NL + - "" + NL + - "" + NL + - "" + NL + + "" + NL + "" + NL + "" + NL + + "" + NL + + "" + NL + + "" + NL + + "" + NL + - "" + NL + - "" + NL + - "" + NL + + "" + NL + "" + NL + "" + NL + + "" + NL + + "" + NL + - "" + NL + - "" + "Packages with annotations of type " + + "AnnotationType" + NL + + "" + NL + "" + NL + "" + NL + "" + NL + + "" + NL + + "" }, {BUG_ID + FS + "pkg" + FS + "class-use" + FS + "AnnotationType.html", - "Classes in pkg with annotations of type AnnotationType" + NL + - "" + NL + - "" + NL + - "" + NL + - "" + NL + "" + NL + "" + NL + + "" + NL + + "" + NL + + "" + NL + + "" + NL + - "" + NL + - "" + NL + - "" + NL + "" + NL + "" + NL + + "" + NL + + "" + NL + + "" + NL + + "" + NL + - "" + NL + - "" + NL + - "" + NL + "" + NL + "" + NL + + "" + NL + + "" + NL + + "" + NL + + "" + NL + - "" + NL + - "" + NL + - "" + NL + "" + NL + "" + NL + + "" + NL + + "" + NL + + "" + NL + + "" + NL + - "" + NL + - "" + NL + "" + NL + "" + NL + + "" + NL + + "" + NL + - "" + NL + - "" + NL + "" + NL + "" + NL + + "" + NL + + ""} }; private static final String[][] NEGATED_TEST = NO_TEST; From 7f2828e070ad79d9bf6c8c7e797abbd344bc1a9e Mon Sep 17 00:00:00 2001 From: Alexey Ushakov Date: Fri, 20 Mar 2009 20:05:22 +0300 Subject: [PATCH 35/75] 6733501: Apply IcedTea little cms patches Reviewed-by: bae, prr --- .../share/native/sun/java2d/cmm/lcms/LCMS.c | 226 +++++++++++++++++- .../share/native/sun/java2d/cmm/lcms/cmsio0.c | 30 ++- .../share/native/sun/java2d/cmm/lcms/lcms.h | 1 + .../cmm/ProfileOp/ReadWriteProfileTest.java | 120 ++++++++++ 4 files changed, 374 insertions(+), 3 deletions(-) create mode 100644 jdk/test/sun/java2d/cmm/ProfileOp/ReadWriteProfileTest.java diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c b/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c index 0573a021876..404ab2e686d 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c @@ -30,6 +30,41 @@ #include "Disposer.h" #include "lcms.h" + +#define ALIGNLONG(x) (((x)+3) & ~(3)) // Aligns to DWORD boundary + +#ifdef USE_BIG_ENDIAN +#define AdjustEndianess32(a) +#else + +static +void AdjustEndianess32(LPBYTE pByte) +{ + BYTE temp1; + BYTE 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 +icInt32Number TransportValue32(icInt32Number Value) +{ + icInt32Number Temp = Value; + + AdjustEndianess32((LPBYTE) &Temp); + return Temp; +} + #define SigMake(a,b,c,d) \ ( ( ((int) ((unsigned char) (a))) << 24) | \ ( ((int) ((unsigned char) (b))) << 16) | \ @@ -182,6 +217,8 @@ JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_loadProfile sProf.pf = cmsOpenProfileFromMem((LPVOID)dataArray, (DWORD) dataSize); + (*env)->ReleaseByteArrayElements (env, data, dataArray, 0); + if (sProf.pf == NULL) { JNU_ThrowIllegalArgumentException(env, "Invalid profile data"); } @@ -345,7 +382,23 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagData JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_setTagData (JNIEnv *env, jobject obj, jlong id, jint tagSig, jbyteArray data) { - fprintf(stderr, "setTagData operation is not implemented"); + cmsHPROFILE profile; + storeID_t sProf; + jbyte* dataArray; + int tagSize; + + if (tagSig == SigHead) { + J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_setTagData on icSigHead not " + "permitted"); + return; + } + + sProf.j = id; + profile = (cmsHPROFILE) sProf.pf; + dataArray = (*env)->GetByteArrayElements(env, data, 0); + tagSize =(*env)->GetArrayLength(env, data); + _cmsModifyTagData(profile, (icTagSignature) tagSig, dataArray, tagSize); + (*env)->ReleaseByteArrayElements(env, data, dataArray, 0); } void* getILData (JNIEnv *env, jobject img, jint* pDataType, @@ -507,3 +560,174 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_initLCMS PF_ID_fID = (*env)->GetFieldID (env, Pf, "ID", "J"); } + +BOOL _cmsModifyTagData(cmsHPROFILE hProfile, icTagSignature sig, + void *data, size_t size) +{ + BOOL isNew; + int i, idx, delta, count; + LPBYTE padChars[3] = {0, 0, 0}; + LPBYTE beforeBuf, afterBuf, ptr; + size_t beforeSize, afterSize; + icUInt32Number profileSize, temp; + LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; + + isNew = FALSE; + idx = _cmsSearchTag(Icc, sig, FALSE); + if (idx < 0) { + isNew = TRUE; + idx = Icc->TagCount++; + if (Icc->TagCount >= MAX_TABLE_TAG) { + J2dRlsTraceLn1(J2D_TRACE_ERROR, "_cmsModifyTagData: Too many tags " + "(%d)\n", Icc->TagCount); + Icc->TagCount = MAX_TABLE_TAG-1; + return FALSE; + } + } + + /* Read in size from header */ + Icc->Seek(Icc, 0); + Icc->Read(&profileSize, sizeof(icUInt32Number), 1, Icc); + AdjustEndianess32((LPBYTE) &profileSize); + + /* Compute the change in profile size */ + if (isNew) { + delta = sizeof(icTag) + ALIGNLONG(size); + } else { + delta = ALIGNLONG(size) - ALIGNLONG(Icc->TagSizes[idx]); + } + /* Add tag to internal structures */ + ptr = malloc(size); + if (ptr == NULL) { + if(isNew) { + Icc->TagCount--; + } + J2dRlsTraceLn(J2D_TRACE_ERROR, "_cmsModifyTagData: ptr == NULL"); + return FALSE; + } + + if (!Icc->Grow(Icc, delta)) { + free(ptr); + if(isNew) { + Icc->TagCount--; + } + J2dRlsTraceLn(J2D_TRACE_ERROR, + "_cmsModifyTagData: Icc->Grow() == FALSE"); + return FALSE; + } + + /* Compute size of tag data before/after the modified tag */ + beforeSize = ((isNew)?profileSize:Icc->TagOffsets[idx]) - + Icc->TagOffsets[0]; + if (Icc->TagCount == (idx + 1)) { + afterSize = 0; + } else { + afterSize = profileSize - Icc->TagOffsets[idx+1]; + } + /* Make copies of the data before/after the modified tag */ + if (beforeSize > 0) { + beforeBuf = malloc(beforeSize); + if (!beforeBuf) { + if(isNew) { + Icc->TagCount--; + } + free(ptr); + J2dRlsTraceLn(J2D_TRACE_ERROR, + "_cmsModifyTagData: beforeBuf == NULL"); + return FALSE; + } + Icc->Seek(Icc, Icc->TagOffsets[0]); + Icc->Read(beforeBuf, beforeSize, 1, Icc); + } + + if (afterSize > 0) { + afterBuf = malloc(afterSize); + if (!afterBuf) { + free(ptr); + if(isNew) { + Icc->TagCount--; + } + if (beforeSize > 0) { + free(beforeBuf); + } + J2dRlsTraceLn(J2D_TRACE_ERROR, + "_cmsModifyTagData: afterBuf == NULL"); + return FALSE; + } + Icc->Seek(Icc, Icc->TagOffsets[idx+1]); + Icc->Read(afterBuf, afterSize, 1, Icc); + } + + CopyMemory(ptr, data, size); + Icc->TagSizes[idx] = size; + Icc->TagNames[idx] = sig; + if (Icc->TagPtrs[idx]) { + free(Icc->TagPtrs[idx]); + } + Icc->TagPtrs[idx] = ptr; + if (isNew) { + Icc->TagOffsets[idx] = profileSize; + } + + + /* Update the profile size in the header */ + profileSize += delta; + Icc->Seek(Icc, 0); + temp = TransportValue32(profileSize); + Icc->Write(Icc, sizeof(icUInt32Number), &temp); + + + /* Adjust tag offsets: if the tag is new, we must account + for the new tag table entry; otherwise, only those tags after + the modified tag are changed (by delta) */ + if (isNew) { + for (i = 0; i < Icc->TagCount; ++i) { + Icc->TagOffsets[i] += sizeof(icTag); + } + } else { + for (i = idx+1; i < Icc->TagCount; ++i) { + Icc->TagOffsets[i] += delta; + } + } + + /* Write out a new tag table */ + count = 0; + for (i = 0; i < Icc->TagCount; ++i) { + if (Icc->TagNames[i] != 0) { + ++count; + } + } + Icc->Seek(Icc, sizeof(icHeader)); + temp = TransportValue32(count); + Icc->Write(Icc, sizeof(icUInt32Number), &temp); + + for (i = 0; i < Icc->TagCount; ++i) { + if (Icc->TagNames[i] != 0) { + icTag tag; + tag.sig = TransportValue32(Icc->TagNames[i]); + tag.offset = TransportValue32((icInt32Number) Icc->TagOffsets[i]); + tag.size = TransportValue32((icInt32Number) Icc->TagSizes[i]); + Icc->Write(Icc, sizeof(icTag), &tag); + } + } + + /* Write unchanged data before the modified tag */ + if (beforeSize > 0) { + Icc->Write(Icc, beforeSize, beforeBuf); + free(beforeBuf); + } + + /* Write modified tag data */ + Icc->Write(Icc, size, data); + if (size % 4) { + Icc->Write(Icc, 4 - (size % 4), padChars); + } + + /* Write unchanged data after the modified tag */ + if (afterSize > 0) { + Icc->Write(Icc, afterSize, afterBuf); + free(afterBuf); + } + + return TRUE; +} diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c index 1556fa5e8af..d09100d653a 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c @@ -157,14 +157,31 @@ BOOL MemoryWrite(struct _lcms_iccprofile_struct* Icc, size_t size, void *Ptr) if (size == 0) return TRUE; if (ResData != NULL) - CopyMemory(ResData ->Block + Icc ->UsedSpace, Ptr, size); + CopyMemory(ResData ->Block + ResData ->Pointer, Ptr, size); + ResData->Pointer += size; Icc->UsedSpace += size; return TRUE; } +static +BOOL MemoryGrow(struct _lcms_iccprofile_struct* Icc, size_t size) +{ + FILEMEM* ResData = (FILEMEM*) Icc->stream; + + void* newBlock = realloc(ResData->Block, ResData->Size + size); + + if (!newBlock) { + return FALSE; + } + ResData->Block = newBlock; + ResData->Size += size; + return TRUE; +} + + static BOOL MemoryClose(struct _lcms_iccprofile_struct* Icc) { @@ -238,6 +255,13 @@ BOOL FileWrite(struct _lcms_iccprofile_struct* Icc, size_t size, LPVOID Ptr) } +static +BOOL FileGrow(struct _lcms_iccprofile_struct* Icc, size_t size) +{ + return TRUE; +} + + static BOOL FileClose(struct _lcms_iccprofile_struct* Icc) { @@ -382,6 +406,7 @@ LPLCMSICCPROFILE _cmsCreateProfileFromFilePlaceholder(const char* FileName) NewIcc ->Seek = FileSeek; NewIcc ->Tell = FileTell; NewIcc ->Close = FileClose; + NewIcc ->Grow = FileGrow; NewIcc ->Write = NULL; NewIcc ->IsWrite = FALSE; @@ -419,7 +444,8 @@ LPLCMSICCPROFILE _cmsCreateProfileFromMemPlaceholder(LPVOID MemPtr, DWORD dwSize NewIcc ->Seek = MemorySeek; NewIcc ->Tell = MemoryTell; NewIcc ->Close = MemoryClose; - NewIcc ->Write = NULL; + NewIcc ->Grow = MemoryGrow; + NewIcc ->Write = MemoryWrite; NewIcc ->IsWrite = FALSE; diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms.h b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms.h index 81184b098fb..404c1020bb0 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms.h +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms.h @@ -1838,6 +1838,7 @@ typedef struct _lcms_iccprofile_struct { BOOL (* Seek)(struct _lcms_iccprofile_struct* Icc, size_t offset); BOOL (* Close)(struct _lcms_iccprofile_struct* Icc); size_t (* Tell)(struct _lcms_iccprofile_struct* Icc); + BOOL (* Grow)(struct _lcms_iccprofile_struct* Icc, size_t amount); // Writting diff --git a/jdk/test/sun/java2d/cmm/ProfileOp/ReadWriteProfileTest.java b/jdk/test/sun/java2d/cmm/ProfileOp/ReadWriteProfileTest.java new file mode 100644 index 00000000000..dc54d94ab45 --- /dev/null +++ b/jdk/test/sun/java2d/cmm/ProfileOp/ReadWriteProfileTest.java @@ -0,0 +1,120 @@ +/* + * Copyright 2007-2008 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 6476665 6523403 6733501 + * @summary Verifies reading and writing profiles and tags of the standard color + * spaces + * @run main ReadWriteProfileTest + */ +import java.awt.color.ColorSpace; +import java.awt.color.ICC_Profile; +import java.util.*; +import java.nio.*; +import java.util.Hashtable; + +public class ReadWriteProfileTest implements Runnable { + /* Location of the tag sig counter in 4-byte words */ + final static int TAG_COUNT_OFFSET = 32; + + /* Location of the tag sig table in 4-byte words */ + final static int TAG_ELEM_OFFSET = 33; + + static byte[][] profiles; + static int [][] tagSigs; + static Hashtable [] tags; + + static int [] cspaces = {ColorSpace.CS_sRGB, ColorSpace.CS_PYCC, + ColorSpace.CS_LINEAR_RGB, ColorSpace.CS_CIEXYZ, + ColorSpace.CS_GRAY}; + + static String [] csNames = {"sRGB", "PYCC", "LINEAR_RGB", "CIEXYZ", "GRAY"}; + + static void getProfileTags(byte [] data, Hashtable tags) { + ByteBuffer byteBuf = ByteBuffer.wrap(data); + IntBuffer intBuf = byteBuf.asIntBuffer(); + int tagCount = intBuf.get(TAG_COUNT_OFFSET); + intBuf.position(TAG_ELEM_OFFSET); + for (int i = 0; i < tagCount; i++) { + int tagSig = intBuf.get(); + int tagDataOff = intBuf.get(); + int tagSize = intBuf.get(); + + byte [] tagData = new byte[tagSize]; + byteBuf.position(tagDataOff); + byteBuf.get(tagData); + tags.put(tagSig, tagData); + } + } + + static { + profiles = new byte[cspaces.length][]; + tags = new Hashtable[cspaces.length]; + + for (int i = 0; i < cspaces.length; i++) { + ICC_Profile pf = ICC_Profile.getInstance(cspaces[i]); + profiles[i] = pf.getData(); + tags[i] = new Hashtable(); + getProfileTags(profiles[i], tags[i]); + } + } + + public void run() { + for (int i = 0; i < cspaces.length; i++) { + ICC_Profile pf = ICC_Profile.getInstance(cspaces[i]); + byte [] data = pf.getData(); + pf = ICC_Profile.getInstance(data); + if (!Arrays.equals(data, profiles[i])) { + System.err.println("Incorrect result of getData() " + "with " + + csNames[i] + " profile"); + throw new RuntimeException("Incorrect result of getData()"); + } + + for (int tagSig : tags[i].keySet()) { + byte [] tagData = pf.getData(tagSig); + byte [] empty = new byte[tagData.length]; + pf.setData(tagSig, empty); + pf.setData(tagSig, tagData); + + byte [] tagData1 = pf.getData(tagSig); + + if (!Arrays.equals(tagData1, tags[i].get(tagSig))) + { + System.err.println("Incorrect result of getData(int) with" + + " tag " + + Integer.toHexString(tagSig) + + " of " + csNames[i] + " profile"); + + throw new RuntimeException("Incorrect result of " + + "getData(int)"); + } + } + } + } + + public static void main(String [] args) { + ReadWriteProfileTest test = new ReadWriteProfileTest(); + test.run(); + } +} From 34d8fbb5e26e14cea387c6cefbeaa0512d1376d8 Mon Sep 17 00:00:00 2001 From: Bhavesh Patel Date: Fri, 20 Mar 2009 15:50:50 -0700 Subject: [PATCH 36/75] 6820360: Fix for definition list tags nesting adds an extra list tag for package summary page Reviewed-by: jjg --- .../formats/html/HtmlDocletWriter.java | 10 ++++--- .../TestHtmlDefinitionListTag.java | 12 ++++++-- .../pkg1/package-info.java | 29 +++++++++++++++++++ 3 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/pkg1/package-info.java diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java index 74d287dd79b..453b8e8e74a 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java @@ -236,17 +236,19 @@ public class HtmlDocletWriter extends HtmlDocWriter { configuration.tagletManager.getCustomTags(doc), getTagletWriterInstance(false), output); String outputString = output.toString().trim(); - // For RootDoc and ClassDoc, this section is not the definition description - // but the start of definition list. + // For RootDoc, ClassDoc and PackageDoc, this section is not the + // definition description but the start of definition list. if (!outputString.isEmpty()) { - if (!(doc instanceof RootDoc || doc instanceof ClassDoc)) { + if (!(doc instanceof RootDoc || doc instanceof ClassDoc || + doc instanceof PackageDoc)) { printMemberDetailsListStartTag(); dd(); } printTagsInfoHeader(); print(outputString); printTagsInfoFooter(); - if (!(doc instanceof RootDoc || doc instanceof ClassDoc)) + if (!(doc instanceof RootDoc || doc instanceof ClassDoc || + doc instanceof PackageDoc)) ddEnd(); } } diff --git a/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/TestHtmlDefinitionListTag.java b/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/TestHtmlDefinitionListTag.java index 5fa8db63ca5..652de517cb5 100644 --- a/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/TestHtmlDefinitionListTag.java +++ b/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/TestHtmlDefinitionListTag.java @@ -25,7 +25,7 @@ /* * @test - * @bug 6786690 + * @bug 6786690 6820360 * @summary This test verifies the nesting of definition list tags. * @author Bhavesh Patel * @library ../lib/ @@ -36,7 +36,7 @@ public class TestHtmlDefinitionListTag extends JavadocTester { - private static final String BUG_ID = "6786690"; + private static final String BUG_ID = "6786690-6820360"; // Test common to all runs of javadoc. The class signature should print // properly enclosed definition list tags and the Annotation Type @@ -55,6 +55,9 @@ public class TestHtmlDefinitionListTag extends JavadocTester { // serialized form should have properly nested definition list tags // enclosing comments, tags and deprecated information. private static final String[][] TEST_CMNT_DEPR = { + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", "
" + NL + + "
Since:
" + NL + + "
JDK1.0
"}, {BUG_ID + FS + "pkg1" + FS + "C1.html", "
" + NL + "
Since:
" + NL + "
JDK1.0
" + NL + "
See Also:
" + @@ -193,6 +196,9 @@ public class TestHtmlDefinitionListTag extends JavadocTester { // should display properly nested definition list tags for comments, tags // and deprecated information. private static final String[][] TEST_NODEPR = { + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", "
" + NL + + "
Since:
" + NL + + "
JDK1.0
"}, {BUG_ID + FS + "pkg1" + FS + "C1.html", "
" + NL + "
Since:
" + NL + "
JDK1.0
" + NL + "
See Also:
" + @@ -302,6 +308,8 @@ public class TestHtmlDefinitionListTag extends JavadocTester { // Test for valid HTML generation which should not comprise of empty // definition list tags. private static final String[][] NEGATED_TEST = { + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", "
"}, + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", "
" + NL + "
"}, {BUG_ID + FS + "pkg1" + FS + "C1.html", "
"}, {BUG_ID + FS + "pkg1" + FS + "C1.html", "
" + NL + "
"}, {BUG_ID + FS + "pkg1" + FS + "C1.ModalExclusionType.html", "
"}, diff --git a/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/pkg1/package-info.java b/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/pkg1/package-info.java new file mode 100644 index 00000000000..201ea4b6199 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/pkg1/package-info.java @@ -0,0 +1,29 @@ +/* + * 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 package 1. + * + * @since JDK1.0 + */ +package pkg1; From df65a88edb38fec4aee98467c9821c8068414a98 Mon Sep 17 00:00:00 2001 From: Xueming Shen Date: Fri, 20 Mar 2009 16:22:59 -0700 Subject: [PATCH 37/75] 6817475: named-capturing group name started with digit causes PSE exception Need accept the digit as the first char of the group name Reviewed-by: alanb --- jdk/src/share/classes/java/util/regex/Pattern.java | 3 ++- jdk/test/java/util/regex/RegExTest.java | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/jdk/src/share/classes/java/util/regex/Pattern.java b/jdk/src/share/classes/java/util/regex/Pattern.java index 919c1bf3c55..ccbf1140ea5 100644 --- a/jdk/src/share/classes/java/util/regex/Pattern.java +++ b/jdk/src/share/classes/java/util/regex/Pattern.java @@ -2567,7 +2567,8 @@ loop: for(int x=0, offset=0; xy+)z+"), + "xxxyyyzzz", + "8gname", + "yyy"); + //backref Pattern pattern = Pattern.compile("(a*)bc\\1"); check(pattern, "zzzaabcazzz", true); // found "abca" From b1d6f69a580abe9ecc711fd4d0c7629a9ce67391 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Mon, 23 Mar 2009 17:05:48 +0800 Subject: [PATCH 38/75] 6820606: keytool can generate serialno more randomly Reviewed-by: xuelei --- jdk/src/share/classes/sun/security/tools/KeyTool.java | 8 ++++---- .../share/classes/sun/security/x509/CertAndKeyGen.java | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/jdk/src/share/classes/sun/security/tools/KeyTool.java b/jdk/src/share/classes/sun/security/tools/KeyTool.java index a3aa50f435d..163e78fc5cf 100644 --- a/jdk/src/share/classes/sun/security/tools/KeyTool.java +++ b/jdk/src/share/classes/sun/security/tools/KeyTool.java @@ -1072,8 +1072,8 @@ public final class KeyTool { X509CertInfo info = new X509CertInfo(); info.set(X509CertInfo.VALIDITY, interval); - info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber - ((int)(firstDate.getTime()/1000))); + info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber( + new java.util.Random().nextInt() & 0x7fffffff)); info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3)); info.set(X509CertInfo.ALGORITHM_ID, @@ -2121,8 +2121,8 @@ public final class KeyTool { certInfo.set(X509CertInfo.VALIDITY, interval); // Make new serial number - certInfo.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber - ((int)(firstDate.getTime()/1000))); + certInfo.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber( + new java.util.Random().nextInt() & 0x7fffffff)); // Set owner and issuer fields X500Name owner; diff --git a/jdk/src/share/classes/sun/security/x509/CertAndKeyGen.java b/jdk/src/share/classes/sun/security/x509/CertAndKeyGen.java index 38ca600927b..2cf34c871ec 100644 --- a/jdk/src/share/classes/sun/security/x509/CertAndKeyGen.java +++ b/jdk/src/share/classes/sun/security/x509/CertAndKeyGen.java @@ -265,8 +265,8 @@ public final class CertAndKeyGen { // Add all mandatory attributes info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3)); - info.set(X509CertInfo.SERIAL_NUMBER, - new CertificateSerialNumber((int)(firstDate.getTime()/1000))); + info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber( + new java.util.Random().nextInt() & 0x7fffffff)); AlgorithmId algID = issuer.getAlgorithmId(); info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algID)); From 3f0b988cfc8d0cd062d366da0db0cc2e2f094f3a Mon Sep 17 00:00:00 2001 From: Xueming Shen Date: Mon, 23 Mar 2009 09:19:23 -0700 Subject: [PATCH 39/75] 6636323: Optimize handling of builtin charsets 6636319: Encoders should implement isLegalReplacement(byte[] repl) Optimized new String(byte[], cs/csn) and String.getBytes(cs/csn) for speed and memory consumption in singlebyte case. Reviewed-by: alanb --- jdk/make/java/nio/FILES_java.gmk | 2 + .../share/classes/java/lang/StringCoding.java | 188 +++++++++++----- .../classes/sun/nio/cs/ArrayDecoder.java | 35 +++ .../classes/sun/nio/cs/ArrayEncoder.java | 35 +++ .../share/classes/sun/nio/cs/ISO_8859_1.java | 54 ++++- .../share/classes/sun/nio/cs/SingleByte.java | 59 +++++- .../share/classes/sun/nio/cs/US_ASCII.java | 59 +++++- jdk/test/sun/nio/cs/FindEncoderBugs.java | 1 - jdk/test/sun/nio/cs/StrCodingBenchmark.java | 200 ++++++++++++++++++ jdk/test/sun/nio/cs/TestStringCoding.java | 151 +++++++++++++ 10 files changed, 711 insertions(+), 73 deletions(-) create mode 100644 jdk/src/share/classes/sun/nio/cs/ArrayDecoder.java create mode 100644 jdk/src/share/classes/sun/nio/cs/ArrayEncoder.java create mode 100644 jdk/test/sun/nio/cs/StrCodingBenchmark.java create mode 100644 jdk/test/sun/nio/cs/TestStringCoding.java diff --git a/jdk/make/java/nio/FILES_java.gmk b/jdk/make/java/nio/FILES_java.gmk index 5027274f209..637b8dc4f96 100644 --- a/jdk/make/java/nio/FILES_java.gmk +++ b/jdk/make/java/nio/FILES_java.gmk @@ -220,6 +220,8 @@ FILES_src = \ sun/nio/ch/Util.java \ \ sun/nio/cs/AbstractCharsetProvider.java \ + sun/nio/cs/ArrayDecoder.java \ + sun/nio/cs/ArrayEncoder.java \ sun/nio/cs/FastCharsetProvider.java \ sun/nio/cs/HistoricallyNamedCharset.java \ sun/nio/cs/ISO_8859_1.java \ diff --git a/jdk/src/share/classes/java/lang/StringCoding.java b/jdk/src/share/classes/java/lang/StringCoding.java index 833fdf5f603..885db317af5 100644 --- a/jdk/src/share/classes/java/lang/StringCoding.java +++ b/jdk/src/share/classes/java/lang/StringCoding.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-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 @@ -25,13 +25,10 @@ package java.lang; -import java.io.CharConversionException; import java.io.UnsupportedEncodingException; import java.lang.ref.SoftReference; import java.nio.ByteBuffer; import java.nio.CharBuffer; -import java.nio.BufferOverflowException; -import java.nio.BufferUnderflowException; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; @@ -39,11 +36,12 @@ import java.nio.charset.CharacterCodingException; import java.nio.charset.CoderResult; import java.nio.charset.CodingErrorAction; import java.nio.charset.IllegalCharsetNameException; -import java.nio.charset.MalformedInputException; import java.nio.charset.UnsupportedCharsetException; import java.util.Arrays; import sun.misc.MessageUtils; import sun.nio.cs.HistoricallyNamedCharset; +import sun.nio.cs.ArrayDecoder; +import sun.nio.cs.ArrayEncoder; /** * Utility class for string encoding and decoding. @@ -74,10 +72,8 @@ class StringCoding { // Trim the given byte array to the given length // - private static byte[] safeTrim(byte[] ba, int len, Charset cs) { - if (len == ba.length - && (System.getSecurityManager() == null - || cs.getClass().getClassLoader0() == null)) + private static byte[] safeTrim(byte[] ba, int len, Charset cs, boolean isTrusted) { + if (len == ba.length && (isTrusted || System.getSecurityManager() == null)) return ba; else return Arrays.copyOf(ba, len); @@ -85,10 +81,9 @@ class StringCoding { // Trim the given char array to the given length // - private static char[] safeTrim(char[] ca, int len, Charset cs) { - if (len == ca.length - && (System.getSecurityManager() == null - || cs.getClass().getClassLoader0() == null)) + private static char[] safeTrim(char[] ca, int len, + Charset cs, boolean isTrusted) { + if (len == ca.length && (isTrusted || System.getSecurityManager() == null)) return ca; else return Arrays.copyOf(ca, len); @@ -128,6 +123,7 @@ class StringCoding { private final String requestedCharsetName; private final Charset cs; private final CharsetDecoder cd; + private final boolean isTrusted; private StringDecoder(Charset cs, String rcn) { this.requestedCharsetName = rcn; @@ -135,6 +131,7 @@ class StringCoding { this.cd = cs.newDecoder() .onMalformedInput(CodingErrorAction.REPLACE) .onUnmappableCharacter(CodingErrorAction.REPLACE); + this.isTrusted = (cs.getClass().getClassLoader0() == null); } String charsetName() { @@ -152,24 +149,28 @@ class StringCoding { char[] ca = new char[en]; if (len == 0) return ca; - cd.reset(); - ByteBuffer bb = ByteBuffer.wrap(ba, off, len); - CharBuffer cb = CharBuffer.wrap(ca); - try { - CoderResult cr = cd.decode(bb, cb, true); - if (!cr.isUnderflow()) - cr.throwException(); - cr = cd.flush(cb); - if (!cr.isUnderflow()) - cr.throwException(); - } catch (CharacterCodingException x) { - // Substitution is always enabled, - // so this shouldn't happen - throw new Error(x); + if (cd instanceof ArrayDecoder) { + int clen = ((ArrayDecoder)cd).decode(ba, off, len, ca); + return safeTrim(ca, clen, cs, isTrusted); + } else { + cd.reset(); + ByteBuffer bb = ByteBuffer.wrap(ba, off, len); + CharBuffer cb = CharBuffer.wrap(ca); + try { + CoderResult cr = cd.decode(bb, cb, true); + if (!cr.isUnderflow()) + cr.throwException(); + cr = cd.flush(cb); + if (!cr.isUnderflow()) + cr.throwException(); + } catch (CharacterCodingException x) { + // Substitution is always enabled, + // so this shouldn't happen + throw new Error(x); + } + return safeTrim(ca, cb.position(), cs, isTrusted); } - return safeTrim(ca, cb.position(), cs); } - } static char[] decode(String charsetName, byte[] ba, int off, int len) @@ -193,8 +194,57 @@ class StringCoding { } static char[] decode(Charset cs, byte[] ba, int off, int len) { - StringDecoder sd = new StringDecoder(cs, cs.name()); - return sd.decode(Arrays.copyOfRange(ba, off, off + len), 0, len); + // (1)We never cache the "external" cs, the only benefit of creating + // an additional StringDe/Encoder object to wrap it is to share the + // de/encode() method. These SD/E objects are short-lifed, the young-gen + // gc should be able to take care of them well. But the best approash + // is still not to generate them if not really necessary. + // (2)The defensive copy of the input byte/char[] has a big performance + // impact, as well as the outgoing result byte/char[]. Need to do the + // optimization check of (sm==null && classLoader0==null) for both. + // (3)getClass().getClassLoader0() is expensive + // (4)There might be a timing gap in isTrusted setting. getClassLoader0() + // is only chcked (and then isTrusted gets set) when (SM==null). It is + // possible that the SM==null for now but then SM is NOT null later + // when safeTrim() is invoked...the "safe" way to do is to redundant + // check (... && (isTrusted || SM == null || getClassLoader0())) in trim + // but it then can be argued that the SM is null when the opertaion + // is started... + CharsetDecoder cd = cs.newDecoder(); + int en = scale(len, cd.maxCharsPerByte()); + char[] ca = new char[en]; + if (len == 0) + return ca; + boolean isTrusted = false; + if (System.getSecurityManager() != null) { + if (!(isTrusted = (cs.getClass().getClassLoader0() == null))) { + ba = Arrays.copyOfRange(ba, off, off + len); + off = 0; + } + } + if (cd instanceof ArrayDecoder) { + int clen = ((ArrayDecoder)cd).decode(ba, off, len, ca); + return safeTrim(ca, clen, cs, isTrusted); + } else { + cd.onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE) + .reset(); + ByteBuffer bb = ByteBuffer.wrap(ba, off, len); + CharBuffer cb = CharBuffer.wrap(ca); + try { + CoderResult cr = cd.decode(bb, cb, true); + if (!cr.isUnderflow()) + cr.throwException(); + cr = cd.flush(cb); + if (!cr.isUnderflow()) + cr.throwException(); + } catch (CharacterCodingException x) { + // Substitution is always enabled, + // so this shouldn't happen + throw new Error(x); + } + return safeTrim(ca, cb.position(), cs, isTrusted); + } } static char[] decode(byte[] ba, int off, int len) { @@ -218,14 +268,12 @@ class StringCoding { } } - - - // -- Encoding -- private static class StringEncoder { private Charset cs; private CharsetEncoder ce; private final String requestedCharsetName; + private final boolean isTrusted; private StringEncoder(Charset cs, String rcn) { this.requestedCharsetName = rcn; @@ -233,6 +281,7 @@ class StringCoding { this.ce = cs.newEncoder() .onMalformedInput(CodingErrorAction.REPLACE) .onUnmappableCharacter(CodingErrorAction.REPLACE); + this.isTrusted = (cs.getClass().getClassLoader0() == null); } String charsetName() { @@ -250,23 +299,27 @@ class StringCoding { byte[] ba = new byte[en]; if (len == 0) return ba; - - ce.reset(); - ByteBuffer bb = ByteBuffer.wrap(ba); - CharBuffer cb = CharBuffer.wrap(ca, off, len); - try { - CoderResult cr = ce.encode(cb, bb, true); - if (!cr.isUnderflow()) - cr.throwException(); - cr = ce.flush(bb); - if (!cr.isUnderflow()) - cr.throwException(); - } catch (CharacterCodingException x) { - // Substitution is always enabled, - // so this shouldn't happen - throw new Error(x); + if (ce instanceof ArrayEncoder) { + int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba); + return safeTrim(ba, blen, cs, isTrusted); + } else { + ce.reset(); + ByteBuffer bb = ByteBuffer.wrap(ba); + CharBuffer cb = CharBuffer.wrap(ca, off, len); + try { + CoderResult cr = ce.encode(cb, bb, true); + if (!cr.isUnderflow()) + cr.throwException(); + cr = ce.flush(bb); + if (!cr.isUnderflow()) + cr.throwException(); + } catch (CharacterCodingException x) { + // Substitution is always enabled, + // so this shouldn't happen + throw new Error(x); + } + return safeTrim(ba, bb.position(), cs, isTrusted); } - return safeTrim(ba, bb.position(), cs); } } @@ -291,8 +344,39 @@ class StringCoding { } static byte[] encode(Charset cs, char[] ca, int off, int len) { - StringEncoder se = new StringEncoder(cs, cs.name()); - return se.encode(Arrays.copyOfRange(ca, off, off + len), 0, len); + CharsetEncoder ce = cs.newEncoder(); + int en = scale(len, ce.maxBytesPerChar()); + byte[] ba = new byte[en]; + if (len == 0) + return ba; + boolean isTrusted = false; + if (System.getSecurityManager() != null) { + if (!(isTrusted = (cs.getClass().getClassLoader0() == null))) { + ca = Arrays.copyOfRange(ca, off, off + len); + off = 0; + } + } + if (ce instanceof ArrayEncoder) { + int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba); + return safeTrim(ba, blen, cs, isTrusted); + } else { + ce.onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE) + .reset(); + ByteBuffer bb = ByteBuffer.wrap(ba); + CharBuffer cb = CharBuffer.wrap(ca, off, len); + try { + CoderResult cr = ce.encode(cb, bb, true); + if (!cr.isUnderflow()) + cr.throwException(); + cr = ce.flush(bb); + if (!cr.isUnderflow()) + cr.throwException(); + } catch (CharacterCodingException x) { + throw new Error(x); + } + return safeTrim(ba, bb.position(), cs, isTrusted); + } } static byte[] encode(char[] ca, int off, int len) { diff --git a/jdk/src/share/classes/sun/nio/cs/ArrayDecoder.java b/jdk/src/share/classes/sun/nio/cs/ArrayDecoder.java new file mode 100644 index 00000000000..daff5ec39d1 --- /dev/null +++ b/jdk/src/share/classes/sun/nio/cs/ArrayDecoder.java @@ -0,0 +1,35 @@ +/* + * 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.nio.cs; + +/* + * FastPath byte[]->char[] decoder, REPLACE on malformed or + * unmappable input. + */ + +public interface ArrayDecoder { + int decode(byte[] src, int off, int len, char[] dst); +} diff --git a/jdk/src/share/classes/sun/nio/cs/ArrayEncoder.java b/jdk/src/share/classes/sun/nio/cs/ArrayEncoder.java new file mode 100644 index 00000000000..1eb4726f70b --- /dev/null +++ b/jdk/src/share/classes/sun/nio/cs/ArrayEncoder.java @@ -0,0 +1,35 @@ +/* + * 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.nio.cs; + +/* + * FastPath char[]->byte[] encoder, REPLACE on malformed input or + * unmappable input. + */ + +public interface ArrayEncoder { + int encode(char[] src, int off, int len, byte[] dst); +} diff --git a/jdk/src/share/classes/sun/nio/cs/ISO_8859_1.java b/jdk/src/share/classes/sun/nio/cs/ISO_8859_1.java index ad27a1507ac..7eb3b5b8a83 100644 --- a/jdk/src/share/classes/sun/nio/cs/ISO_8859_1.java +++ b/jdk/src/share/classes/sun/nio/cs/ISO_8859_1.java @@ -23,9 +23,6 @@ * have any questions. */ -/* - */ - package sun.nio.cs; import java.nio.ByteBuffer; @@ -34,10 +31,7 @@ import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; -import java.nio.charset.CharacterCodingException; -import java.nio.charset.MalformedInputException; -import java.nio.charset.UnmappableCharacterException; - +import java.util.Arrays; class ISO_8859_1 extends Charset @@ -65,8 +59,8 @@ class ISO_8859_1 return new Encoder(this); } - private static class Decoder extends CharsetDecoder { - + private static class Decoder extends CharsetDecoder + implements ArrayDecoder { private Decoder(Charset cs) { super(cs, 1.0f, 1.0f); } @@ -127,10 +121,18 @@ class ISO_8859_1 return decodeBufferLoop(src, dst); } + public int decode(byte[] src, int sp, int len, char[] dst) { + if (len > dst.length) + len = dst.length; + int dp = 0; + while (dp < len) + dst[dp++] = (char)(src[sp++] & 0xff); + return dp; + } } - private static class Encoder extends CharsetEncoder { - + private static class Encoder extends CharsetEncoder + implements ArrayEncoder { private Encoder(Charset cs) { super(cs, 1.0f, 1.0f); } @@ -139,6 +141,10 @@ class ISO_8859_1 return c <= '\u00FF'; } + public boolean isLegalReplacement(byte[] repl) { + return (repl.length == 1); // we accept any byte value + } + private final Surrogate.Parser sgp = new Surrogate.Parser(); private CoderResult encodeArrayLoop(CharBuffer src, @@ -208,5 +214,31 @@ class ISO_8859_1 return encodeBufferLoop(src, dst); } + private byte repl = (byte)'?'; + protected void implReplaceWith(byte[] newReplacement) { + repl = newReplacement[0]; + } + + public int encode(char[] src, int sp, int len, byte[] dst) { + int dp = 0; + int sl = sp + Math.min(len, dst.length); + while (sp < sl) { + char c = src[sp++]; + if (c <= '\u00FF') { + dst[dp++] = (byte)c; + continue; + } + if (Surrogate.isHigh(c) && sp < sl && + Surrogate.isLow(src[sp])) { + if (len > dst.length) { + sl++; + len--; + } + sp++; + } + dst[dp++] = repl; + } + return dp; + } } } diff --git a/jdk/src/share/classes/sun/nio/cs/SingleByte.java b/jdk/src/share/classes/sun/nio/cs/SingleByte.java index fdbf4e3c643..9b0531eebd9 100644 --- a/jdk/src/share/classes/sun/nio/cs/SingleByte.java +++ b/jdk/src/share/classes/sun/nio/cs/SingleByte.java @@ -32,6 +32,7 @@ import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; +import java.util.Arrays; import static sun.nio.cs.CharsetMapping.*; public class SingleByte @@ -45,7 +46,8 @@ public class SingleByte return cr; } - public static class Decoder extends CharsetDecoder { + final public static class Decoder extends CharsetDecoder + implements ArrayDecoder { private final char[] b2c; public Decoder(Charset cs, char[] b2c) { @@ -108,9 +110,29 @@ public class SingleByte private final char decode(int b) { return b2c[b + 128]; } + + private char repl = '\uFFFD'; + protected void implReplaceWith(String newReplacement) { + repl = newReplacement.charAt(0); + } + + public int decode(byte[] src, int sp, int len, char[] dst) { + if (len > dst.length) + len = dst.length; + int dp = 0; + while (dp < len) { + dst[dp] = decode(src[sp++]); + if (dst[dp] == UNMAPPABLE_DECODING) { + dst[dp] = repl; + } + dp++; + } + return dp; + } } - public static class Encoder extends CharsetEncoder { + final public static class Encoder extends CharsetEncoder + implements ArrayEncoder { private Surrogate.Parser sgp; private final char[] c2b; private final char[] c2bIndex; @@ -125,6 +147,11 @@ public class SingleByte return encode(c) != UNMAPPABLE_ENCODING; } + public boolean isLegalReplacement(byte[] repl) { + return ((repl.length == 1 && repl[0] == (byte)'?') || + super.isLegalReplacement(repl)); + } + private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) { char[] sa = src.array(); int sp = src.arrayOffset() + src.position(); @@ -200,6 +227,34 @@ public class SingleByte return UNMAPPABLE_ENCODING; return c2b[index + (ch & 0xff)]; } + + private byte repl = (byte)'?'; + protected void implReplaceWith(byte[] newReplacement) { + repl = newReplacement[0]; + } + + public int encode(char[] src, int sp, int len, byte[] dst) { + int dp = 0; + int sl = sp + Math.min(len, dst.length); + while (sp < sl) { + char c = src[sp++]; + int b = encode(c); + if (b != UNMAPPABLE_ENCODING) { + dst[dp++] = (byte)b; + continue; + } + if (Surrogate.isHigh(c) && sp < sl && + Surrogate.isLow(src[sp])) { + if (len > dst.length) { + sl++; + len--; + } + sp++; + } + dst[dp++] = repl; + } + return dp; + } } // init the c2b and c2bIndex tables from b2c. diff --git a/jdk/src/share/classes/sun/nio/cs/US_ASCII.java b/jdk/src/share/classes/sun/nio/cs/US_ASCII.java index d22fa64e352..fa718450768 100644 --- a/jdk/src/share/classes/sun/nio/cs/US_ASCII.java +++ b/jdk/src/share/classes/sun/nio/cs/US_ASCII.java @@ -31,10 +31,7 @@ import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; -import java.nio.charset.CharacterCodingException; -import java.nio.charset.MalformedInputException; -import java.nio.charset.UnmappableCharacterException; - +import java.util.Arrays; public class US_ASCII extends Charset @@ -61,7 +58,8 @@ public class US_ASCII return new Encoder(this); } - private static class Decoder extends CharsetDecoder { + private static class Decoder extends CharsetDecoder + implements ArrayDecoder { private Decoder(Charset cs) { super(cs, 1.0f, 1.0f); @@ -131,9 +129,27 @@ public class US_ASCII return decodeBufferLoop(src, dst); } + private char repl = '\uFFFD'; + protected void implReplaceWith(String newReplacement) { + repl = newReplacement.charAt(0); + } + + public int decode(byte[] src, int sp, int len, char[] dst) { + int dp = 0; + len = Math.min(len, dst.length); + while (dp < len) { + byte b = src[sp++]; + if (b >= 0) + dst[dp++] = (char)b; + else + dst[dp++] = repl; + } + return dp; + } } - private static class Encoder extends CharsetEncoder { + private static class Encoder extends CharsetEncoder + implements ArrayEncoder { private Encoder(Charset cs) { super(cs, 1.0f, 1.0f); @@ -143,8 +159,11 @@ public class US_ASCII return c < 0x80; } - private final Surrogate.Parser sgp = new Surrogate.Parser(); + public boolean isLegalReplacement(byte[] repl) { + return (repl.length == 1 && repl[0] >= 0); + } + private final Surrogate.Parser sgp = new Surrogate.Parser(); private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) { @@ -213,6 +232,32 @@ public class US_ASCII return encodeBufferLoop(src, dst); } + private byte repl = (byte)'?'; + protected void implReplaceWith(byte[] newReplacement) { + repl = newReplacement[0]; + } + + public int encode(char[] src, int sp, int len, byte[] dst) { + int dp = 0; + int sl = sp + Math.min(len, dst.length); + while (sp < sl) { + char c = src[sp++]; + if (c < 0x80) { + dst[dp++] = (byte)c; + continue; + } + if (Surrogate.isHigh(c) && sp < sl && + Surrogate.isLow(src[sp])) { + if (len > dst.length) { + sl++; + len--; + } + sp++; + } + dst[dp++] = repl; + } + return dp; + } } } diff --git a/jdk/test/sun/nio/cs/FindEncoderBugs.java b/jdk/test/sun/nio/cs/FindEncoderBugs.java index 0f4c406d453..54bc5b268a0 100644 --- a/jdk/test/sun/nio/cs/FindEncoderBugs.java +++ b/jdk/test/sun/nio/cs/FindEncoderBugs.java @@ -526,4 +526,3 @@ public class FindEncoderBugs { System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); if (failed > 0) throw new AssertionError("Some tests failed");} } - diff --git a/jdk/test/sun/nio/cs/StrCodingBenchmark.java b/jdk/test/sun/nio/cs/StrCodingBenchmark.java new file mode 100644 index 00000000000..73256eb2b43 --- /dev/null +++ b/jdk/test/sun/nio/cs/StrCodingBenchmark.java @@ -0,0 +1,200 @@ +/* + * Copyright (c) 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. + */ + +import java.util.*; +import java.nio.*; +import java.nio.charset.*; +import java.util.concurrent.*; +import java.util.regex.Pattern; + +/** + * Usage: java StringCodingBenchmark + * [-Diterations=N] [-Dsize=N] [-Dsubsize=N] [-Dmaxchar=N] + * [-Dfilter=REGEXP] [-DSecurityManager=true] + */ +public class StrCodingBenchmark { + abstract static class Job { + private final String name; + public Job(String name) { this.name = name; } + public String name() { return name; } + public abstract void work() throws Throwable; + } + + private static void collectAllGarbage() { + final java.util.concurrent.CountDownLatch drained + = new java.util.concurrent.CountDownLatch(1); + try { + System.gc(); // enqueue finalizable objects + new Object() { protected void finalize() { + drained.countDown(); }}; + System.gc(); // enqueue detector + drained.await(); // wait for finalizer queue to drain + System.gc(); // cleanup finalized objects + } catch (InterruptedException e) { throw new Error(e); } + } + + /** + * Runs each job for long enough that all the runtime compilers + * have had plenty of time to warm up, i.e. get around to + * compiling everything worth compiling. + * Returns array of average times per job per run. + */ + public static long[] time0(Job ... jobs) throws Throwable { + //final long warmupNanos = 10L * 1000L * 1000L * 1000L; + final long warmupNanos = 100L * 100L; + long[] nanoss = new long[jobs.length]; + for (int i = 0; i < jobs.length; i++) { + collectAllGarbage(); + long t0 = System.nanoTime(); + long t; + int j = 0; + do { jobs[i].work(); j++; } + while ((t = System.nanoTime() - t0) < warmupNanos); + nanoss[i] = t/j; + } + return nanoss; + } + + public static void time(Job ... jobs) throws Throwable { + + long[] warmup = time0(jobs); // Warm up run + long[] nanoss = time0(jobs); // Real timing run + long[] milliss = new long[jobs.length]; + double[] ratios = new double[jobs.length]; + + final String nameHeader = "Method"; + final String millisHeader = "Millis"; + final String ratioHeader = "Ratio"; + + int nameWidth = nameHeader.length(); + int millisWidth = millisHeader.length(); + int ratioWidth = ratioHeader.length(); + + for (int i = 0; i < jobs.length; i++) { + nameWidth = Math.max(nameWidth, jobs[i].name().length()); + + milliss[i] = nanoss[i]/(1000L * 1000L); + millisWidth = Math.max(millisWidth, + String.format("%d", milliss[i]).length()); + + ratios[i] = (double) nanoss[i] / (double) nanoss[0]; + ratioWidth = Math.max(ratioWidth, + String.format("%.3f", ratios[i]).length()); + } + String format = String.format("%%-%ds %%%dd %n", + nameWidth, millisWidth); + String headerFormat = String.format("%%-%ds %%%ds%n", + nameWidth, millisWidth); + System.out.printf(headerFormat, "Method", "Millis"); + + // Print out absolute and relative times, calibrated against first job + for (int i = 0; i < jobs.length; i++) + System.out.printf(format, jobs[i].name(), milliss[i], ratios[i]); + } + + public static Job[] filter(Pattern filter, Job[] jobs) { + if (filter == null) return jobs; + Job[] newJobs = new Job[jobs.length]; + int n = 0; + for (Job job : jobs) + if (filter.matcher(job.name()).find()) + newJobs[n++] = job; + // Arrays.copyOf not available in JDK 5 + Job[] ret = new Job[n]; + System.arraycopy(newJobs, 0, ret, 0, n); + return ret; + } + + static class PermissiveSecurityManger extends SecurityManager { + @Override public void checkPermission(java.security.Permission p) { + } + } + + public static void main(String[] args) throws Throwable { + final int itrs = Integer.getInteger("iterations", 100000); + final int size = Integer.getInteger("size", 2048); + final int subsize = Integer.getInteger("subsize", 128); + final int maxchar = Integer.getInteger("maxchar", 128); + final String regex = System.getProperty("filter"); + final Pattern filter = (regex == null) ? null : Pattern.compile(regex); + final boolean useSecurityManager = Boolean.getBoolean("SecurityManager"); + if (useSecurityManager) + System.setSecurityManager(new PermissiveSecurityManger()); + final Random rnd = new Random(); + + for (Charset charset: Charset.availableCharsets().values()) { + if (!("ISO-8859-1".equals(charset.name()) || + "US-ASCII".equals(charset.name()) || + charset.newDecoder() instanceof sun.nio.cs.SingleByte.Decoder)) + continue; + final String csn = charset.name(); + final Charset cs = charset; + final StringBuilder sb = new StringBuilder(); + { + final CharsetEncoder enc = cs.newEncoder(); + for (int i = 0; i < size; ) { + char c = (char) rnd.nextInt(maxchar); + if (enc.canEncode(c)) { + sb.append(c); + i++; + } + } + } + final String string = sb.toString(); + final byte[] bytes = string.getBytes(cs); + + System.out.printf("%n--------%s---------%n", csn); + for (int sz = 4; sz <= 2048; sz *= 2) { + System.out.printf(" [len=%d]%n", sz); + final byte[] bs = Arrays.copyOf(bytes, sz); + final String str = new String(bs, csn); + Job[] jobs = { + new Job("String decode: csn") { + public void work() throws Throwable { + for (int i = 0; i < itrs; i++) + new String(bs, csn); + }}, + + new Job("String decode: cs") { + public void work() throws Throwable { + for (int i = 0; i < itrs; i++) + new String(bs, cs); + }}, + + new Job("String encode: csn") { + public void work() throws Throwable { + for (int i = 0; i < itrs; i++) + str.getBytes(csn); + }}, + + new Job("String encode: cs") { + public void work() throws Throwable { + for (int i = 0; i < itrs; i++) + str.getBytes(cs); + }}, + }; + time(filter(filter, jobs)); + } + } + } +} diff --git a/jdk/test/sun/nio/cs/TestStringCoding.java b/jdk/test/sun/nio/cs/TestStringCoding.java new file mode 100644 index 00000000000..8d0c8f94f24 --- /dev/null +++ b/jdk/test/sun/nio/cs/TestStringCoding.java @@ -0,0 +1,151 @@ +/* + * Copyright 2000-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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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 6636323 6636319 + @summary Test if StringCoding and NIO result have the same de/encoding result + * @run main/timeout=2000 TestStringCoding + */ + +import java.util.*; +import java.nio.*; +import java.nio.charset.*; + +public class TestStringCoding { + public static void main(String[] args) throws Throwable { + + for (Boolean hasSM: new boolean[] { false, true }) { + if (hasSM) + System.setSecurityManager(new PermissiveSecurityManger()); + for (Charset cs: Charset.availableCharsets().values()) { + if ("ISO-2022-CN".equals(cs.name()) || + "x-COMPOUND_TEXT".equals(cs.name()) || + "x-JISAutoDetect".equals(cs.name())) + continue; + System.out.printf("Testing(sm=%b) " + cs.name() + "....", hasSM); + // full bmp first + char[] bmpCA = new char[0x10000]; + for (int i = 0; i < 0x10000; i++) { + bmpCA[i] = (char)i; + } + byte[] sbBA = new byte[0x100]; + for (int i = 0; i < 0x100; i++) { + sbBA[i] = (byte)i; + } + test(cs, bmpCA, sbBA); + // "randomed" sizes + Random rnd = new Random(); + for (int i = 0; i < 10; i++) { + int clen = rnd.nextInt(0x10000); + int blen = rnd.nextInt(0x100); + //System.out.printf(" blen=%d, clen=%d%n", blen, clen); + test(cs, Arrays.copyOf(bmpCA, clen), Arrays.copyOf(sbBA, blen)); + //add a pair of surrogates + int pos = clen / 2; + if ((pos + 1) < blen) { + bmpCA[pos] = '\uD800'; + bmpCA[pos+1] = '\uDC00'; + } + test(cs, Arrays.copyOf(bmpCA, clen), Arrays.copyOf(sbBA, blen)); + } + System.out.println("done!"); + } + } + } + + static void test(Charset cs, char[] bmpCA, byte[] sbBA) throws Throwable { + String bmpStr = new String(bmpCA); + CharsetDecoder dec = cs.newDecoder() + .onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE); + CharsetEncoder enc = cs.newEncoder() + .onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE); + + //getBytes(csn); + byte[] baSC = bmpStr.getBytes(cs.name()); + ByteBuffer bf = enc.reset().encode(CharBuffer.wrap(bmpCA)); + byte[] baNIO = new byte[bf.limit()]; + bf.get(baNIO, 0, baNIO.length); + if (!Arrays.equals(baSC, baNIO)) + throw new RuntimeException("getBytes(csn) failed -> " + cs.name()); + + //getBytes(cs); + baSC = bmpStr.getBytes(cs); + if (!Arrays.equals(baSC, baNIO)) + throw new RuntimeException("getBytes(cs) failed -> " + cs.name()); + + //new String(csn); + String strSC = new String(sbBA, cs.name()); + String strNIO = dec.reset().decode(ByteBuffer.wrap(sbBA)).toString(); + if(!strNIO.equals(strSC)) + throw new RuntimeException("new String(csn) failed -> " + cs.name()); + + //new String(cs); + strSC = new String(sbBA, cs); + if (!strNIO.equals(strSC)) + throw new RuntimeException("new String(cs) failed -> " + cs.name()); + + //encode unmappable surrogates + if (enc instanceof sun.nio.cs.ArrayEncoder && + cs.contains(Charset.forName("ASCII"))) { + enc.replaceWith(new byte[] { (byte)'A'}); + sun.nio.cs.ArrayEncoder cae = (sun.nio.cs.ArrayEncoder)enc; + + String str = "ab\uD800\uDC00\uD800\uDC00cd"; + byte[] ba = new byte[str.length() - 2]; + int n = cae.encode(str.toCharArray(), 0, str.length(), ba); + if (n != 6 || !"abAAcd".equals(new String(ba, cs.name()))) + throw new RuntimeException("encode1(surrogates) failed -> " + + cs.name()); + + ba = new byte[str.length()]; + n = cae.encode(str.toCharArray(), 0, str.length(), ba); + if (n != 6 || !"abAAcd".equals(new String(ba, 0, n, + cs.name()))) + throw new RuntimeException("encode2(surrogates) failed -> " + + cs.name()); + str = "ab\uD800B\uDC00Bcd"; + ba = new byte[str.length()]; + n = cae.encode(str.toCharArray(), 0, str.length(), ba); + if (n != 8 || !"abABABcd".equals(new String(ba, 0, n, + cs.name()))) + throw new RuntimeException("encode3(surrogates) failed -> " + + cs.name()); + + ba = new byte[str.length() - 1]; + n = cae.encode(str.toCharArray(), 0, str.length(), ba); + if (n != 7 || !"abABABc".equals(new String(ba, 0, n, + cs.name()))) + throw new RuntimeException("encode4(surrogates) failed -> " + + cs.name()); + } + + } + + static class PermissiveSecurityManger extends SecurityManager { + @Override public void checkPermission(java.security.Permission p) {} + } +} From 4db0a48b104dab588360861e4fbb3c21c94d826e Mon Sep 17 00:00:00 2001 From: Phil Race Date: Mon, 23 Mar 2009 10:40:54 -0700 Subject: [PATCH 40/75] 6745225: Memory leak while drawing Attributed String Reviewed-by: jgodinez, dougfelt --- .../classes/sun/font/FileFontStrike.java | 23 ++++- .../share/classes/sun/font/GlyphLayout.java | 2 + .../awt/font/LineBreakMeasurer/FRCTest.java | 90 +++++++++++++++++++ 3 files changed, 111 insertions(+), 4 deletions(-) create mode 100644 jdk/test/java/awt/font/LineBreakMeasurer/FRCTest.java diff --git a/jdk/src/share/classes/sun/font/FileFontStrike.java b/jdk/src/share/classes/sun/font/FileFontStrike.java index 4628016a216..11dff8a20c1 100644 --- a/jdk/src/share/classes/sun/font/FileFontStrike.java +++ b/jdk/src/share/classes/sun/font/FileFontStrike.java @@ -26,6 +26,7 @@ package sun.font; import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; import java.awt.Font; import java.awt.GraphicsEnvironment; import java.awt.Rectangle; @@ -842,15 +843,29 @@ public class FileFontStrike extends PhysicalStrike { return fileFont.getGlyphOutlineBounds(pScalerContext, glyphCode); } - private ConcurrentHashMap outlineMap; + private + WeakReference> outlineMapRef; GeneralPath getGlyphOutline(int glyphCode, float x, float y) { - if (outlineMap == null) { - outlineMap = new ConcurrentHashMap(); + + GeneralPath gp = null; + ConcurrentHashMap outlineMap = null; + + if (outlineMapRef != null) { + outlineMap = outlineMapRef.get(); + if (outlineMap != null) { + gp = (GeneralPath)outlineMap.get(glyphCode); + } } - GeneralPath gp = (GeneralPath)outlineMap.get(glyphCode); + if (gp == null) { gp = fileFont.getGlyphOutline(pScalerContext, glyphCode, 0, 0); + if (outlineMap == null) { + outlineMap = new ConcurrentHashMap(); + outlineMapRef = + new WeakReference + >(outlineMap); + } outlineMap.put(glyphCode, gp); } gp = (GeneralPath)gp.clone(); // mutable! diff --git a/jdk/src/share/classes/sun/font/GlyphLayout.java b/jdk/src/share/classes/sun/font/GlyphLayout.java index 18ebec85a02..91162cb1c57 100644 --- a/jdk/src/share/classes/sun/font/GlyphLayout.java +++ b/jdk/src/share/classes/sun/font/GlyphLayout.java @@ -338,6 +338,8 @@ public final class GlyphLayout { cache = new ConcurrentHashMap(10); cacheRef = new SoftReference>(cache); + } else if (cache.size() >= 512) { + cache.clear(); } cache.put(key, res); } diff --git a/jdk/test/java/awt/font/LineBreakMeasurer/FRCTest.java b/jdk/test/java/awt/font/LineBreakMeasurer/FRCTest.java new file mode 100644 index 00000000000..d65037e2ec3 --- /dev/null +++ b/jdk/test/java/awt/font/LineBreakMeasurer/FRCTest.java @@ -0,0 +1,90 @@ +/* + * Copyright 2008-9 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 6448405 6519513 6745225 + * @summary static HashMap cache in LineBreakMeasurer can grow wihout bounds + * @run main/othervm/timeout=600 -client -Xms16m -Xmx16m FRCTest + */ +import java.awt.*; +import java.awt.image.*; +import java.awt.font.*; +import java.awt.geom.*; +import java.text.*; +import java.util.Hashtable; + +public class FRCTest { + + static AttributedString vanGogh = new AttributedString( + "Many people believe that Vincent van Gogh painted his best works " + + "during the two-year period he spent in Provence. Here is where he " + + "painted The Starry Night--which some consider to be his greatest " + + "work of all. However, as his artistic brilliance reached new " + + "heights in Provence, his physical and mental health plummeted. ", + new Hashtable()); + + public static void main(String[] args) { + + // First test the behaviour of Graphics2D.getFontRenderContext(); + BufferedImage bi = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB); + Graphics2D g2d = bi.createGraphics(); + AffineTransform g2dTx = new AffineTransform(2,0,2,0,1,1); + g2d.setTransform(g2dTx); + AffineTransform frcTx = g2d.getFontRenderContext().getTransform(); + AffineTransform frcExpected = new AffineTransform(2,0,2,0,0,0); + if (!frcTx.equals(frcExpected)) { + throw new RuntimeException("FRC Tx may have translate?"); + } + + // Now test that using different translates with LBM is OK + // This test doesn't prove a lot since showing a leak really + // requires a basher test that can run for a long time. + for (int x=0;x<100;x++) { + for (int y=0;y<100;y++) { + AttributedCharacterIterator aci = vanGogh.getIterator(); + AffineTransform tx = AffineTransform.getTranslateInstance(x, y); + FontRenderContext frc = new FontRenderContext(tx, false, false); + LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc); + lbm.setPosition(aci.getBeginIndex()); + while (lbm.getPosition() < aci.getEndIndex()) { + lbm.nextLayout(100f); + } + } + } + + for (int x=0;x<25;x++) { + for (int y=0;y<25;y++) { + AttributedCharacterIterator aci = vanGogh.getIterator(); + double rot = Math.random()*.4*Math.PI - .2*Math.PI; + AffineTransform tx = AffineTransform.getRotateInstance(rot); + FontRenderContext frc = new FontRenderContext(tx, false, false); + LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc); + lbm.setPosition(aci.getBeginIndex()); + while (lbm.getPosition() < aci.getEndIndex()) { + lbm.nextLayout(100f); + } + } + } + } +} From 283deccd890a1e0f002c63b0bd956e715f0a1ac2 Mon Sep 17 00:00:00 2001 From: Andrew John Hughes Date: Mon, 23 Mar 2009 17:43:15 -0700 Subject: [PATCH 41/75] 6695776: corba jscheme jar files in repository could be built from source Forward port of changes from the 6-open train. Reviewed-by: darcy, ohair, tbell --- corba/make/com/sun/corba/se/sources/Makefile | 10 +- corba/make/sun/rmi/corbalogsources/Makefile | 49 +- corba/make/tools/Makefile | 3 +- corba/make/tools/logutil/Makefile | 43 ++ .../se/logutil/IndentingPrintWriter.java | 15 +- .../com/sun/tools/corba/se/logutil/Input.java | 211 ++++++ .../sun/tools/corba/se/logutil/InputCode.java | 116 +++ .../corba/se/logutil/InputException.java | 94 +++ .../com/sun/tools/corba/se/logutil/MC.java | 559 +++++++++++++++ .../tools/corba/se/logutil/lib/jscheme.jar | Bin 382167 -> 0 bytes .../corba/se/logutil/lib/jschemelogutil.jar | Bin 2451 -> 0 bytes .../com/sun/tools/corba/se/logutil/scripts/mc | 2 - .../sun/tools/corba/se/logutil/scripts/mc.scm | 662 ------------------ .../sun/tools/corba/se/logutil/scripts/run | 2 - 14 files changed, 1059 insertions(+), 707 deletions(-) create mode 100644 corba/make/tools/logutil/Makefile create mode 100644 corba/src/share/classes/com/sun/tools/corba/se/logutil/Input.java create mode 100644 corba/src/share/classes/com/sun/tools/corba/se/logutil/InputCode.java create mode 100644 corba/src/share/classes/com/sun/tools/corba/se/logutil/InputException.java create mode 100644 corba/src/share/classes/com/sun/tools/corba/se/logutil/MC.java delete mode 100644 corba/src/share/classes/com/sun/tools/corba/se/logutil/lib/jscheme.jar delete mode 100644 corba/src/share/classes/com/sun/tools/corba/se/logutil/lib/jschemelogutil.jar delete mode 100644 corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/mc delete mode 100644 corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/mc.scm delete mode 100644 corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/run diff --git a/corba/make/com/sun/corba/se/sources/Makefile b/corba/make/com/sun/corba/se/sources/Makefile index 164a4e65a93..9d945a29343 100644 --- a/corba/make/com/sun/corba/se/sources/Makefile +++ b/corba/make/com/sun/corba/se/sources/Makefile @@ -46,8 +46,6 @@ CORBA_JMK_DIRECTORY=$(TOPDIR)/make/com/sun/corba/minclude/ include $(CORBA_JMK_DIRECTORY)com_sun_corba_se_PortableActivationIDL.jmk include $(CORBA_JMK_DIRECTORY)com_sun_corba_se_impl_logging.jmk -FILES_java += com/sun/corba/se/org/omg/CORBA/ORB.java - # # Dirs # @@ -80,11 +78,11 @@ ORBUTIL.MC = $(SRC_DIR)/com/sun/corba/se/spi/logging/data/ORBUtil.mc POA.MC = $(SRC_DIR)/com/sun/corba/se/spi/logging/data/POA.mc UTIL.MC = $(SRC_DIR)/com/sun/corba/se/spi/logging/data/Util.mc -MC_GENERATE_CLASS = $(SRC_DIR)/com/sun/tools/corba/se/logutil/scripts/mc.scm -main main make-class -MC_GENERATE_LOG_RB = $(SRC_DIR)/com/sun/tools/corba/se/logutil/scripts/mc.scm -main main make-resource +MC_GENERATE_CLASS = make-class +MC_GENERATE_LOG_RB = make-resource -JSCHEME_GENERATE_CLASS = $(BOOT_JAVA_CMD) jscheme.REPL $(MC_GENERATE_CLASS) -JSCHEME_GENERATE_LOG_RB = $(BOOT_JAVA_CMD) jscheme.REPL $(MC_GENERATE_LOG_RB) +JSCHEME_GENERATE_CLASS = $(BOOT_JAVA_CMD) com.sun.tools.corba.se.logutil.MC $(MC_GENERATE_CLASS) +JSCHEME_GENERATE_LOG_RB = $(BOOT_JAVA_CMD) com.sun.tools.corba.se.logutil.MC $(MC_GENERATE_LOG_RB) # diff --git a/corba/make/sun/rmi/corbalogsources/Makefile b/corba/make/sun/rmi/corbalogsources/Makefile index a7b995c1c51..0859c5ab2a9 100644 --- a/corba/make/sun/rmi/corbalogsources/Makefile +++ b/corba/make/sun/rmi/corbalogsources/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2003-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 @@ -75,15 +75,14 @@ ORBUTIL.MC = $(SRC_DIR)/com/sun/corba/se/spi/logging/data/ORBUtil.mc POA.MC = $(SRC_DIR)/com/sun/corba/se/spi/logging/data/POA.mc UTIL.MC = $(SRC_DIR)/com/sun/corba/se/spi/logging/data/Util.mc -MC_GENERATE_CLASS = $(SRC_DIR)/com/sun/tools/corba/se/logutil/scripts/mc.scm -main main make-class -MC_GENERATE_LOG_RB = $(SRC_DIR)/com/sun/tools/corba/se/logutil/scripts/mc.scm -main main make-resource +MC_GENERATE_CLASS = make-class +MC_GENERATE_LOG_RB = make-resource -JSCHEME_LIB_DIRECTORY=$(SRC_DIR)/com/sun/tools/corba/se/logutil/lib -JSCHEME_CLASSPATH=$(JSCHEME_LIB_DIRECTORY)/jscheme.jar$(CLASSPATH_SEPARATOR)$(JSCHEME_LIB_DIRECTORY)/jschemelogutil.jar -JSCHEME_GENERATE_CLASS = $(BOOT_JAVA_CMD) \ - -cp "$(JSCHEME_CLASSPATH)" jscheme.REPL $(MC_GENERATE_CLASS) -JSCHEME_GENERATE_LOG_RB = $(BOOT_JAVA_CMD) \ - -cp "$(JSCHEME_CLASSPATH)" jscheme.REPL $(MC_GENERATE_LOG_RB) +MC_CLASSPATH=$(BUILDTOOLJARDIR)/MC.jar +MCJ_GENERATE_CLASS = $(BOOT_JAVA_CMD) \ + -cp "$(MC_CLASSPATH)" com.sun.tools.corba.se.logutil.MC $(MC_GENERATE_CLASS) +MCJ_GENERATE_LOG_RB = $(BOOT_JAVA_CMD) \ + -cp "$(MC_CLASSPATH)" com.sun.tools.corba.se.logutil.MC $(MC_GENERATE_LOG_RB) # @@ -104,28 +103,28 @@ $(LOG_GENDIRECTORY): $(MKDIR) -p $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/ActivationSystemException.java : $(ACTIVATION.MC) - $(JSCHEME_GENERATE_CLASS) $(ACTIVATION.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_CLASS) $(ACTIVATION.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/IORSystemException.java : $(IOR.MC) - $(JSCHEME_GENERATE_CLASS) $(IOR.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_CLASS) $(IOR.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/InterceptorsSystemException.java : $(INTERCEPTORS.MC) - $(JSCHEME_GENERATE_CLASS) $(INTERCEPTORS.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_CLASS) $(INTERCEPTORS.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/NamingSystemException.java : $(NAMING.MC) - $(JSCHEME_GENERATE_CLASS) $(NAMING.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_CLASS) $(NAMING.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/OMGSystemException.java : $(OMG.MC) - $(JSCHEME_GENERATE_CLASS) $(OMG.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_CLASS) $(OMG.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/ORBUtilSystemException.java : $(ORBUTIL.MC) - $(JSCHEME_GENERATE_CLASS) $(ORBUTIL.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_CLASS) $(ORBUTIL.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/POASystemException.java : $(POA.MC) - $(JSCHEME_GENERATE_CLASS) $(POA.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_CLASS) $(POA.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/UtilSystemException.java : $(UTIL.MC) - $(JSCHEME_GENERATE_CLASS) $(UTIL.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_CLASS) $(UTIL.MC) $(LOG_GENDIRECTORY) logresource.generate: $(LOG_GENDIRECTORY)/LogStrings.properties @@ -142,28 +141,28 @@ $(LOG_GENDIRECTORY)/LogStrings.properties: \ $(CAT) $(LOG_GENDIRECTORY)/*.resource > $(LOG_GENDIRECTORY)/LogStrings.properties $(LOG_GENDIRECTORY)/ActivationSystemException.resource : $(ACTIVATION.MC) - $(JSCHEME_GENERATE_LOG_RB) $(ACTIVATION.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_LOG_RB) $(ACTIVATION.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/IORSystemException.resource : $(IOR.MC) - $(JSCHEME_GENERATE_LOG_RB) $(IOR.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_LOG_RB) $(IOR.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/InterceptorsSystemException.resource : $(INTERCEPTORS.MC) - $(JSCHEME_GENERATE_LOG_RB) $(INTERCEPTORS.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_LOG_RB) $(INTERCEPTORS.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/NamingSystemException.resource : $(NAMING.MC) - $(JSCHEME_GENERATE_LOG_RB) $(NAMING.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_LOG_RB) $(NAMING.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/OMGSystemException.resource : $(OMG.MC) - $(JSCHEME_GENERATE_LOG_RB) $(OMG.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_LOG_RB) $(OMG.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/ORBUtilSystemException.resource : $(ORBUTIL.MC) - $(JSCHEME_GENERATE_LOG_RB) $(ORBUTIL.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_LOG_RB) $(ORBUTIL.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/POASystemException.resource : $(POA.MC) - $(JSCHEME_GENERATE_LOG_RB) $(POA.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_LOG_RB) $(POA.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/UtilSystemException.resource : $(UTIL.MC) - $(JSCHEME_GENERATE_LOG_RB) $(UTIL.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_LOG_RB) $(UTIL.MC) $(LOG_GENDIRECTORY) # diff --git a/corba/make/tools/Makefile b/corba/make/tools/Makefile index 489c7b2f269..f0d95363b84 100644 --- a/corba/make/tools/Makefile +++ b/corba/make/tools/Makefile @@ -1,5 +1,5 @@ # -# Copyright 1998-2005 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 1998-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 @@ -33,6 +33,7 @@ include $(BUILDDIR)/common/Defs.gmk SUBDIRS = \ strip_properties \ idlj \ + logutil \ all build clean clobber:: $(SUBDIRS-loop) diff --git a/corba/make/tools/logutil/Makefile b/corba/make/tools/logutil/Makefile new file mode 100644 index 00000000000..2e19867f8d4 --- /dev/null +++ b/corba/make/tools/logutil/Makefile @@ -0,0 +1,43 @@ +# +# Copyright 2008 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. Sun designates this +# particular file as subject to the "Classpath" exception as provided +# by Sun in the LICENSE file that accompanied this code. +# +# 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. +# + +# +# Makefile for building the idlj tool +# + +BUILDDIR = ../.. +PACKAGE = com.sun.tools.corba.se.logutil +PRODUCT = tools +PROGRAM = MC +include $(BUILDDIR)/common/Defs.gmk + +BUILDTOOL_SOURCE_ROOT = $(SHARE_SRC)/classes +BUILDTOOL_MAIN = $(PKGDIR)/MC.java + +# +# Build tool jar rules. +# +include $(BUILDDIR)/common/BuildToolJar.gmk + diff --git a/corba/src/share/classes/com/sun/tools/corba/se/logutil/IndentingPrintWriter.java b/corba/src/share/classes/com/sun/tools/corba/se/logutil/IndentingPrintWriter.java index d8b31fc0f77..e618a7401fa 100644 --- a/corba/src/share/classes/com/sun/tools/corba/se/logutil/IndentingPrintWriter.java +++ b/corba/src/share/classes/com/sun/tools/corba/se/logutil/IndentingPrintWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-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 @@ -30,7 +30,6 @@ import java.io.Writer ; import java.io.OutputStream ; import java.io.BufferedWriter ; import java.io.OutputStreamWriter ; -import jsint.Pair ; import java.util.StringTokenizer ; public class IndentingPrintWriter extends PrintWriter { @@ -38,22 +37,20 @@ public class IndentingPrintWriter extends PrintWriter { private int indentWidth = 4 ; private String indentString = "" ; - public void printMsg( String msg, Pair data ) + public void printMsg( String msg, Object... data ) { // System.out.println( "printMsg called with msg=" + msg + " data=" + data ) ; StringTokenizer st = new StringTokenizer( msg, "@", true ) ; StringBuffer result = new StringBuffer() ; - Object head = data.first ; - Pair tail = (Pair)data.rest ; String token = null ; + int pos = 0; while (st.hasMoreTokens()) { token = st.nextToken() ; if (token.equals("@")) { - if (head != null) { - result.append( head ) ; - head = tail.first ; - tail = (Pair)tail.rest ; + if (pos < data.length) { + result.append( data[pos] ); + ++pos; } else { throw new Error( "List too short for message" ) ; } diff --git a/corba/src/share/classes/com/sun/tools/corba/se/logutil/Input.java b/corba/src/share/classes/com/sun/tools/corba/se/logutil/Input.java new file mode 100644 index 00000000000..5431f0c7a17 --- /dev/null +++ b/corba/src/share/classes/com/sun/tools/corba/se/logutil/Input.java @@ -0,0 +1,211 @@ +/* + * Copyright 2008 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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. + */ + +package com.sun.tools.corba.se.logutil; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStreamReader; +import java.io.IOException; + +import java.util.LinkedList; +import java.util.Queue; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Input { + + /** + * The name of the package this class will inhabit. + */ + private String packageName; + + /** + * The name of the generated class. + */ + private String className; + + /** + * The name of the group of exceptions handled by the class. + */ + private String groupName; + + /** + * The group of exceptions. + */ + private Queue exceptions; + + /** + * Represents the current state of parsing the input. + */ + private enum State + { + OUTER, + IN_CLASS, + IN_EXCEPTION_LIST + }; + + /** + * Regular expression to match each code line. + */ + private static final Pattern EXCEPTION_INFO_REGEX = + Pattern.compile("(\\w+)\\s*(\\d+)\\s*(\\w+)"); + + /** + * Parses the specified file to create a new {@link Input} + * object. + * + * @param filename the file to parse. + * @throws FileNotFoundException if the file can't be found. + * @throws IOException if an I/O error occurs. + */ + public Input(final String filename) + throws FileNotFoundException, IOException { + BufferedReader r = + new BufferedReader(new InputStreamReader(new FileInputStream(filename))); + State state = State.OUTER; + InputException current = null; + exceptions = new LinkedList(); + String line; + while ((line = r.readLine()) != null) { + // Skip ; comments + if (line.startsWith(";")) + continue; + + int index = line.indexOf("("); + if (index == -1) + continue; + + switch (state) { + case OUTER: + state = State.IN_CLASS; + String[] classInfo = line.substring(index).split(" "); + packageName = classInfo[0].substring(2, classInfo[0].length() - 1); + className = classInfo[1].substring(1, classInfo[1].length() - 1); + groupName = classInfo[2]; + break; + case IN_CLASS: + state = State.IN_EXCEPTION_LIST; + break; + case IN_EXCEPTION_LIST: + boolean inQuote = false; + boolean inCode = false; + boolean end = false; + int start = index + 1; + Queue lines = new LinkedList(); + for (int a = start; a < line.length(); ++a) { + if (line.charAt(a) == '(' && !inCode && !inQuote) { + if (current == null) + current = + new InputException(line.substring(start, a).trim()); + start = a + 1; + inCode = true; + } + if (line.charAt(a) == '"') + inQuote = !inQuote; + if (line.charAt(a) == ')' && !inQuote) { + if (inCode) { + lines.offer(line.substring(start, a)); + inCode = false; + } else + end = true; + } + if (!end && a == line.length() - 1) + line += r.readLine(); + } + for (String l : lines) { + int stringStart = l.indexOf("\"") + 1; + int stringEnd = l.indexOf("\"", stringStart); + Matcher matcher = EXCEPTION_INFO_REGEX.matcher(l.substring(0, stringStart)); + if (matcher.find()) + current.add(new InputCode(matcher.group(1), + Integer.parseInt(matcher.group(2)), + matcher.group(3), + l.substring(stringStart, stringEnd))); + } + exceptions.offer(current); + current = null; + break; + } + } + } + + /** + * Returns the name of this group of exceptions. + * + * @return the name of this group of exceptions. + */ + public String getGroupName() + { + return groupName; + } + + /** + * Returns the name of the package this class will go in. + * + * @return the name of the package. + */ + public String getPackageName() + { + return packageName; + } + + /** + * Returns the name of the generated class. + * + * @return the name of the class. + */ + public String getClassName() + { + return className; + } + + /** + * Returns the exceptions contained in this class. + * + * @return the exceptions. + */ + public Queue getExceptions() { + return exceptions; + } + + /** + * Returns a textual representation of this input. + * + * @return a textual representation. + */ + public String toString() { + return getClass().getName() + + "[packageName=" + packageName + + ",className=" + className + + ",groupName=" + groupName + + ",exceptions=" + exceptions + + "]"; + } + +} diff --git a/corba/src/share/classes/com/sun/tools/corba/se/logutil/InputCode.java b/corba/src/share/classes/com/sun/tools/corba/se/logutil/InputCode.java new file mode 100644 index 00000000000..810a449f486 --- /dev/null +++ b/corba/src/share/classes/com/sun/tools/corba/se/logutil/InputCode.java @@ -0,0 +1,116 @@ +/* + * Copyright 2008 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.sun.tools.corba.se.logutil; + +public class InputCode { + + /** + * The name of this code. + */ + private final String name; + + /** + * The code. + */ + private final int code; + + /** + * The log level for this code. + */ + private final String logLevel; + + /** + * The error message for this code. + */ + private final String message; + + /** + * Creates a new error code with the specified name, code, + * log level and error message. + * + * @param name the name of the new code. + * @param code the code itself. + * @param logLevel the level of severity of this error. + * @param message the error message for this code. + */ + public InputCode(final String name, final int code, + final String logLevel, final String message) { + this.name = name; + this.code = code; + this.logLevel = logLevel; + this.message = message; + } + + /** + * Returns the name of this code. + * + * @return the name of the code. + */ + public String getName() { + return name; + } + + /** + * Returns the code. + * + * @return the code. + */ + public int getCode() { + return code; + } + + /** + * Returns the severity of this code. + * + * @return the log level severity of the code. + */ + public String getLogLevel() { + return logLevel; + } + + /** + * Returns the error message for this code. + * + * @return the error message for this code. + */ + public String getMessage() { + return message; + } + + /** + * Returns a textual representation of this code. + * + * @return a textual representation. + */ + public String toString() { + return getClass().getName() + + "[name=" + name + + ",code=" + code + + ",logLevel=" + logLevel + + ",message=" + message + + "]"; + } + +} diff --git a/corba/src/share/classes/com/sun/tools/corba/se/logutil/InputException.java b/corba/src/share/classes/com/sun/tools/corba/se/logutil/InputException.java new file mode 100644 index 00000000000..5c1f4984e57 --- /dev/null +++ b/corba/src/share/classes/com/sun/tools/corba/se/logutil/InputException.java @@ -0,0 +1,94 @@ +/* + * Copyright 2008 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.sun.tools.corba.se.logutil; + +import java.util.LinkedList; +import java.util.Queue; + +public class InputException { + + /** + * The name of this exception. + */ + private final String name; + + /** + * The codes associated with this exception. + */ + private final Queue codes; + + /** + * Constructs a new {@link InputException} with the + * specified name. + * + * @param name the name of the new exception; + */ + public InputException(final String name) { + this.name = name; + codes = new LinkedList(); + } + + /** + * Adds a new code to this exception. + * + * @param c the code to add. + */ + public void add(InputCode c) + { + codes.offer(c); + } + + /** + * Returns the name of this exception. + * + * @return the exception's name. + */ + public String getName() { + return name; + } + + /** + * Returns the codes associated with this exception. + * + * @return the exception's codes. + */ + public Queue getCodes() { + return codes; + } + + /** + * Returns a textual representation of this exception. + * + * @return a textual representation. + */ + public String toString() { + return getClass().getName() + + "[name=" + name + + ",codes=" + codes + + "]"; + } + +} + diff --git a/corba/src/share/classes/com/sun/tools/corba/se/logutil/MC.java b/corba/src/share/classes/com/sun/tools/corba/se/logutil/MC.java new file mode 100644 index 00000000000..9246f70c3ab --- /dev/null +++ b/corba/src/share/classes/com/sun/tools/corba/se/logutil/MC.java @@ -0,0 +1,559 @@ +/* + * Copyright 2008 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.sun.tools.corba.se.logutil; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + +import java.util.Arrays; +import java.util.Date; +import java.util.Formatter; +import java.util.List; +import java.util.Queue; + +public class MC { + + private static final String VERSION = "1.0"; + + private static final List SUN_EXCEPTION_GROUPS = Arrays.asList(new String[] + { "SUNBASE", "ORBUTIL", "ACTIVATION", "NAMING", "INTERCEPTORS", "POA", "IOR", "UTIL" }); + + private static final List EXCEPTIONS = Arrays.asList(new String[] + { "UNKNOWN", "BAD_PARAM", "NO_MEMORY", "IMP_LIMIT", "COMM_FAILURE", "INV_OBJREF", "NO_PERMISSION", + "INTERNAL", "MARSHAL", "INITIALIZE", "NO_IMPLEMENT", "BAD_TYPECODE", "BAD_OPERATION", "NO_RESOURCES", + "NO_RESPONSE", "PERSIST_STORE", "BAD_INV_ORDER", "TRANSIENT", "FREE_MEM", "INV_IDENT", "INV_FLAG", + "INTF_REPOS", "BAD_CONTEXT", "OBJ_ADAPTER", "DATA_CONVERSION", "OBJECT_NOT_EXIST", "TRANSACTION_REQUIRED", + "TRANSACTION_ROLLEDBACK", "INVALID_TRANSACTION", "INV_POLICY", "CODESET_INCOMPATIBLE", "REBIND", + "TIMEOUT", "TRANSACTION_UNAVAILABLE", "BAD_QOS", "INVALID_ACTIVITY", "ACTIVITY_COMPLETED", + "ACTIVITY_REQUIRED" }); + + /** + * Read the minor codes from the input file and + * write out a resource file. + * + * @param inFile the file to read the codes from. + * @param outDir the directory to write the resource file to. + * @throws FileNotFoundException if the input file can not be found. + * @throws IOException if an I/O error occurs. + */ + private void makeResource(String inFile, String outDir) + throws FileNotFoundException, IOException { + writeResource(outDir, new Input(inFile)); + } + + /** + * Create a new Java source file using the specified Scheme input file, + * and writing the result to the given output directory. + * + * @param inFile the file to read the data from. + * @param outDir the directory to write the Java class to. + * @throws FileNotFoundException if the input file can not be found. + * @throws IOException if an I/O error occurs. + */ + private void makeClass(String inFile, String outDir) + throws FileNotFoundException, IOException { + writeClass(inFile, outDir, new Input(inFile)); + } + + /** + * Writes out a Java source file using the data from the given + * {@link Input} object. The result is written to {@code outDir}. + * The name of the input file is just used in the header of the + * resulting source file. + * + * @param inFile the name of the file the data was read from. + * @param outDir the directory to write the Java class to. + * @param input the parsed input data. + * @throws FileNotFoundException if the output file can't be written. + */ + private void writeClass(String inFile, String outDir, Input input) + throws FileNotFoundException { + String packageName = input.getPackageName(); + String className = input.getClassName(); + String groupName = input.getGroupName(); + Queue exceptions = input.getExceptions(); + FileOutputStream file = new FileOutputStream(outDir + File.separator + className + ".java"); + IndentingPrintWriter pw = new IndentingPrintWriter(file); + + writeClassHeader(inFile, groupName, pw); + pw.printMsg("package @ ;", packageName); + pw.println(); + pw.println("import java.util.logging.Logger ;"); + pw.println("import java.util.logging.Level ;"); + pw.println(); + pw.println("import org.omg.CORBA.OMGVMCID ;"); + pw.println( "import com.sun.corba.se.impl.util.SUNVMCID ;"); + pw.println( "import org.omg.CORBA.CompletionStatus ;"); + pw.println( "import org.omg.CORBA.SystemException ;"); + pw.println(); + pw.println( "import com.sun.corba.se.spi.orb.ORB ;"); + pw.println(); + pw.println( "import com.sun.corba.se.spi.logging.LogWrapperFactory;"); + pw.println(); + pw.println( "import com.sun.corba.se.spi.logging.LogWrapperBase;"); + pw.println(); + writeImports(exceptions, pw); + pw.println(); + pw.indent(); + pw.printMsg("public class @ extends LogWrapperBase {", className); + pw.println(); + pw.printMsg("public @( Logger logger )", className); + pw.indent(); + pw.println( "{"); + pw.undent(); + pw.println( "super( logger ) ;"); + pw.println( "}"); + pw.println(); + pw.flush(); + writeFactoryMethod(className, groupName, pw); + writeExceptions(groupName, exceptions, className, pw); + pw.undent(); + pw.println( ); + pw.println( "}"); + pw.flush(); + pw.close(); + } + + /** + * Writes out the header of a Java source file. + * + * @param inFile the input file the file was generated from. + * @param groupName the group of exceptions the Java source file is for. + * @param pw the print writer used to write the output. + */ + private void writeClassHeader(String inFile, String groupName, + IndentingPrintWriter pw) { + if (groupName.equals("OMG")) + pw.println("// Log wrapper class for standard exceptions"); + else + pw.printMsg("// Log wrapper class for Sun private system exceptions in group @", + groupName); + pw.println("//"); + pw.printMsg("// Generated by MC.java version @, DO NOT EDIT BY HAND!", VERSION); + pw.printMsg("// Generated from input file @ on @", inFile, new Date()); + pw.println(); + } + + /** + * Write out the import list for the exceptions. + * + * @param groups the exceptions that were parsed. + * @param pw the {@link IndentingPrintWriter} for writing to the file. + */ + private void writeImports(Queue exceptions, + IndentingPrintWriter pw) { + if (exceptions == null) + return; + for (InputException e : exceptions) + pw.println("import org.omg.CORBA." + e.getName() + " ;"); + } + + /** + * Write out the factory method for this group of exceptions. + * + * @param className the name of the generated class. + * @param groupName the name of this group of exceptions. + * @param pw the {@link IndentingPrintWriter} for writing to the file. + */ + private void writeFactoryMethod(String className, String groupName, + IndentingPrintWriter pw) { + pw.indent(); + pw.println( "private static LogWrapperFactory factory = new LogWrapperFactory() {"); + pw.println( "public LogWrapperBase create( Logger logger )" ); + pw.indent(); + pw.println( "{"); + pw.undent(); + pw.printMsg("return new @( logger ) ;", className); + pw.undent(); + pw.println( "}" ); + pw.println( "} ;" ); + pw.println(); + pw.printMsg("public static @ get( ORB orb, String logDomain )", className); + pw.indent(); + pw.println( "{"); + pw.indent(); + pw.printMsg( "@ wrapper = ", className); + pw.indent(); + pw.printMsg( "(@) orb.getLogWrapper( logDomain, ", className); + pw.undent(); + pw.undent(); + pw.printMsg( "\"@\", factory ) ;", groupName); + pw.undent(); + pw.println( "return wrapper ;" ); + pw.println( "} " ); + pw.println(); + pw.printMsg( "public static @ get( String logDomain )", className); + pw.indent(); + pw.println( "{"); + pw.indent(); + pw.printMsg( "@ wrapper = ", className); + pw.indent(); + pw.printMsg( "(@) ORB.staticGetLogWrapper( logDomain, ", className); + pw.undent(); + pw.undent(); + pw.printMsg( "\"@\", factory ) ;", groupName); + pw.undent(); + pw.println( "return wrapper ;" ); + pw.println( "} " ); + pw.println(); + } + + /** + * Writes out the exceptions themselves. + * + * @param groupName the name of this group of exceptions. + * @param exceptions the exceptions to write out. + * @param className the name of the generated class. + * @param pw the {@link IndentingPrintWriter} for writing to the file. + */ + private void writeExceptions(String groupName, Queue exceptions, + String className, IndentingPrintWriter pw) { + for (InputException e : exceptions) { + pw.println("///////////////////////////////////////////////////////////"); + pw.printMsg("// @", e.getName()); + pw.println("///////////////////////////////////////////////////////////"); + pw.println(); + for (InputCode c : e.getCodes()) + writeMethods(groupName, e.getName(), c.getName(), c.getCode(), + c.getLogLevel(), className, StringUtil.countArgs(c.getMessage()), pw); + pw.flush(); + } + } + + /** + * Writes out the methods for a particular error. + * + * @param groupName the name of this group of exceptions. + * @param exceptionName the name of this particular exception. + * @param errorName the name of this particular error. + * @param code the minor code for this particular error. + * @param ident the name of the error in mixed-case identifier form. + * @param level the level at which to place log messages. + * @param className the name of the class for this group of exceptions. + * @param numParams the number of parameters the detail message takes. + * @param pw the print writer for writing to the file. + */ + private void writeMethods(String groupName, String exceptionName, String errorName, + int code, String level, String className, int numParams, + IndentingPrintWriter pw) { + String ident = StringUtil.toMixedCase(errorName); + pw.printMsg("public static final int @ = @ ;", errorName, getBase(groupName, code)); + pw.println(); + pw.flush(); + writeMethodStatusCause(groupName, exceptionName, errorName, ident, level, + numParams, className, pw); + pw.println(); + pw.flush(); + writeMethodStatus(exceptionName, ident, numParams, pw); + pw.println(); + pw.flush(); + writeMethodCause(exceptionName, ident, numParams, pw); + pw.println(); + pw.flush(); + writeMethodNoArgs(exceptionName, ident, numParams, pw); + pw.println(); + pw.flush(); + } + + /** + * Writes out a method for an error that takes a + * {@link org.omg.CORBA.CompletionStatus} and a cause. + * + * @param groupName the name of this group of exceptions. + * @param exceptionName the name of this particular exception. + * @param errorName the name of this particular error. + * @param ident the name of the error in mixed-case identifier form. + * @param logLevel the level at which to place log messages. + * @param numParams the number of parameters the detail message takes. + * @param className the name of the class for this group of exceptions. + * @param pw the print writer for writing to the file. + */ + private void writeMethodStatusCause(String groupName, String exceptionName, + String errorName, String ident, + String logLevel, int numParams, + String className, IndentingPrintWriter pw) { + pw.indent(); + pw.printMsg( "public @ @( CompletionStatus cs, Throwable t@) {", exceptionName, + ident, makeDeclArgs(true, numParams)); + pw.printMsg( "@ exc = new @( @, cs ) ;", exceptionName, exceptionName, errorName); + pw.indent(); + pw.println( "if (t != null)" ); + pw.undent(); + pw.println( "exc.initCause( t ) ;" ); + pw.println(); + pw.indent(); + pw.printMsg( "if (logger.isLoggable( Level.@ )) {", logLevel); + if (numParams > 0) { + pw.printMsg( "Object[] parameters = new Object[@] ;", numParams); + for (int a = 0; a < numParams; ++a) + pw.printMsg("parameters[@] = arg@ ;", a, a); + } else + pw.println( "Object[] parameters = null ;"); + pw.indent(); + pw.printMsg( "doLog( Level.@, \"@.@\",", logLevel, groupName, ident); + pw.undent(); + pw.undent(); + pw.printMsg( "parameters, @.class, exc ) ;", className); + pw.println( "}"); + pw.println(); + + pw.undent(); + pw.println( "return exc ;"); + pw.println( "}"); + } + + /** + * Writes out a method for an error that takes a + * {@link org.omg.CORBA.CompletionStatus}. + * + * @param exceptionName the name of this particular exception. + * @param ident the name of the error in mixed-case identifier form. + * @param numParams the number of parameters the detail message takes. + * @param pw the print writer for writing to the file. + */ + private void writeMethodStatus(String exceptionName, String ident, + int numParams, IndentingPrintWriter pw) { + pw.indent(); + pw.printMsg("public @ @( CompletionStatus cs@) {", exceptionName, + ident, makeDeclArgs(true, numParams)); + pw.undent(); + pw.printMsg("return @( cs, null@ ) ;", ident, makeCallArgs(true, numParams)); + pw.println("}"); + } + + /** + * Writes out a method for an error that takes a cause. + * + * @param exceptionName the name of this particular exception. + * @param ident the name of the error in mixed-case identifier form. + * @param numParams the number of parameters the detail message takes. + * @param pw the print writer for writing to the file. + */ + private void writeMethodCause(String exceptionName, String ident, + int numParams, IndentingPrintWriter pw) { + pw.indent(); + pw.printMsg("public @ @( Throwable t@) {", exceptionName, ident, + makeDeclArgs(true, numParams)); + pw.undent(); + pw.printMsg("return @( CompletionStatus.COMPLETED_NO, t@ ) ;", ident, + makeCallArgs(true, numParams)); + pw.println("}"); + } + + /** + * Writes out a method for an error that takes no arguments. + * + * @param exceptionName the name of this particular exception. + * @param ident the name of the error in mixed-case identifier form. + * @param numParams the number of parameters the detail message takes. + * @param pw the print writer for writing to the file. + */ + private void writeMethodNoArgs(String exceptionName, String ident, + int numParams, IndentingPrintWriter pw) { + + pw.indent(); + pw.printMsg("public @ @( @) {", exceptionName, ident, + makeDeclArgs(false, numParams)); + pw.undent(); + pw.printMsg("return @( CompletionStatus.COMPLETED_NO, null@ ) ;", + ident, makeCallArgs(true, numParams)); + pw.println("}"); + } + + /** + * Returns a list of comma-separated arguments with type declarations. + * + * @param leadingComma true if the list should start with a comma. + * @param numArgs the number of arguments to generate. + * @return the generated string. + */ + private String makeDeclArgs(boolean leadingComma, int numArgs) { + return makeArgString("Object arg", leadingComma, numArgs); + } + + /** + * Returns a list of comma-separated arguments without type declarations. + * + * @param leadingComma true if the list should start with a comma. + * @param numArgs the number of arguments to generate. + * @return the generated string. + */ + private String makeCallArgs(boolean leadingComma, int numArgs) { + return makeArgString("arg", leadingComma, numArgs); + } + + /** + * Returns a list of comma-separated arguments. + * + * @param prefixString the string with which to prefix each argument. + * @param leadingComma true if the list should start with a comma. + * @param numArgs the number of arguments to generate. + * @return the generated string. + */ + private String makeArgString(String prefixString, boolean leadingComma, + int numArgs) { + if (numArgs == 0) + return " "; + if (numArgs == 1) { + if (leadingComma) + return ", " + prefixString + (numArgs - 1); + else + return " " + prefixString + (numArgs - 1); + } + return makeArgString(prefixString, leadingComma, numArgs - 1) + + ", " + prefixString + (numArgs - 1); + } + + /** + * Returns the {@link String} containing the calculation of the + * error code. + * + * @param groupName the group of exception to which the code belongs. + * @param code the minor code number representing the exception within the group. + * @return the unique error code. + */ + private String getBase(String groupName, int code) { + if (groupName.equals("OMG")) + return "OMGVMCID.value + " + code; + else + return "SUNVMCID.value + " + (code + getSunBaseNumber(groupName)); + } + + /** + * Returns the base number for Sun-specific exceptions. + * + * @return the base number. + */ + private int getSunBaseNumber(String groupName) { + return 200 * SUN_EXCEPTION_GROUPS.indexOf(groupName); + } + + /** + * Writes out a resource file using the data from the given + * {@link Input} object. The result is written to {@code outDir}. + * + * @param outDir the directory to write the Java class to. + * @param input the parsed input data. + * @throws FileNotFoundException if the output file can't be written. + */ + private void writeResource(String outDir, Input input) + throws FileNotFoundException { + FileOutputStream file = new FileOutputStream(outDir + File.separator + + input.getClassName() + ".resource"); + IndentingPrintWriter pw = new IndentingPrintWriter(file); + String groupName = input.getGroupName(); + for (InputException e : input.getExceptions()) { + String exName = e.getName(); + for (InputCode c : e.getCodes()) { + String ident = StringUtil.toMixedCase(c.getName()); + pw.printMsg("@.@=\"@: (@) @\"", groupName, ident, + getMessageID(groupName, exName, c.getCode()), exName, c.getMessage()); + } + pw.flush(); + } + pw.close(); + } + + /** + * Returns the message ID corresponding to the given group name, + * exception name and error code. + * + * @param groupName the name of the group of exceptions. + * @param exception the name of the particular exception. + * @param code an error code from the given exception. + * @return the message ID. + */ + private String getMessageID(String groupName, String exceptionName, int code) { + if (groupName.equals("OMG")) + return getStandardMessageID(exceptionName, code); + else + return getSunMessageID(groupName, exceptionName, code); + } + + /** + * Returns the standard (OMG) message ID corresponding to the given + * exception name and error code. + * + * @param exceptionName the name of the particular exception. + * @param code an error code from the given exception. + * @return the message ID. + */ + private String getStandardMessageID(String exceptionName, int code) { + return new Formatter().format("IOP%s0%04d", getExceptionID(exceptionName), + code).toString(); + } + + /** + * Returns the Sun message ID corresponding to the given group name, + * exception name and error code. + * + * @param groupName the name of the group of exceptions. + * @param exceptionName the name of the particular exception. + * @param code an error code from the given exception. + * @return the message ID. + */ + private String getSunMessageID(String groupName, String exceptionName, int code) { + return new Formatter().format("IOP%s1%04d", getExceptionID(exceptionName), + getSunBaseNumber(groupName) + code).toString(); + } + + /** + * Returns the exception ID corresponding to the given exception name. + * + * @param exceptionName the name of the particular exception. + * @return the message ID. + */ + private String getExceptionID(String exceptionName) { + return new Formatter().format("%03d", EXCEPTIONS.indexOf(exceptionName)).toString(); + } + + /** + * Entry point for running the generator from the command + * line. Users can specify either "make-class" or "make-resource" + * as the first argument to generate the specified type of file. + * + * @param args the command-line arguments. + * @throws FileNotFoundException if the input file can not be found. + * @throws IOException if an I/O error occurs. + */ + public static void main(String[] args) + throws FileNotFoundException, IOException + { + if (args.length < 3) + { + System.err.println("(make-class|make-resource) "); + System.exit(-1); + } + if (args[0].equals("make-class")) + new MC().makeClass(args[1], args[2]); + else if (args[0].equals("make-resource")) + new MC().makeResource(args[1], args[2]); + else + System.err.println("Invalid command: " + args[0]); + } + +} diff --git a/corba/src/share/classes/com/sun/tools/corba/se/logutil/lib/jscheme.jar b/corba/src/share/classes/com/sun/tools/corba/se/logutil/lib/jscheme.jar deleted file mode 100644 index 5a2a0f1f44dff2c8bb40f08e382cb361852a1408..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 382167 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 z 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

UthMOiAwfddM#*0wgzl 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≪t`{T+x9Zlh|Fj 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 z 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 P;9xF2HUQwnAL{Dgsf6*5 diff --git a/corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/mc b/corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/mc deleted file mode 100644 index 16df63d031f..00000000000 --- a/corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/mc +++ /dev/null @@ -1,2 +0,0 @@ -#! /bin/sh -java -cp lib/jscheme.jar:lib/util.jar jscheme.REPL mc.scm -main main $@ diff --git a/corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/mc.scm b/corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/mc.scm deleted file mode 100644 index 3e9b51409ec..00000000000 --- a/corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/mc.scm +++ /dev/null @@ -1,662 +0,0 @@ -; Scheme program to produce CORBA standard exceptions class -; requires Jscheme Java extensions -; Makes use of some custom Java classes also - -(import "com.sun.tools.corba.se.logutil.IndentingPrintWriter" ) -(import "com.sun.tools.corba.se.logutil.StringUtil" ) -(import "java.io.FileOutputStream") - -(define version-string "1.3") - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Utility functions -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; reload this file (convenience definition) -(define (reload) (load "mc.scm")) - -; Simple little function to report an error -(define (error msg) - (throw (Error. msg))) - -; some debug support -(define debug #f) - -(define (dprint msg) - (if debug - (.println System.out$ msg))) - -; Replace dprint with noprint to avoid seeing messages when debug is #t -(define (noprint msg) ()) - -; Helper function present so that a scheme method taking strings as args -; can be easily run from a command line. -; arg: vector containing argument strings. Element 0 is the function name -; to execute -(define (main arg) - (let* - ( - (arg-list (vector->list arg)) - (function-symbol (string->symbol (car arg-list))) - (args (cdr arg-list))) - (apply (eval function-symbol) args))) - -; Returns the position of key in lst, numbering from 0. key is matched using eqv? -(define (get-list-position key lst) - (letrec - ( - (helper (lambda (k l accum) - (cond - ((null? l) (error (string-append "Could not find " k))) - ((eqv? k (car l)) accum) - (else (helper k (cdr l) (+ accum 1))) )))) - (begin - (noprint (string-append "get-list-position called with key " key " lst " lst )) - (helper key lst 0)))) - -; Return a string representing number in decimal padded to length with leading 0s. -(define (pad-number-string number length) - (let* - ( - (number-string (number->string number)) - (pad-length (- length (string-length number-string))) - ) - (string-append (make-string pad-length #\0) number-string))) - -; Read an S-expression from a file that contains all of the data. -; -; The S-expression used for minor codes must have the structure -; (package-name class-name exception-group-name -; (exception -; (name value level explanation) -; ... -; ) -; ... -; ) -(define (read-file fname) - (read (open-input-file fname))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Functions for handling major system exceptions and exception groups -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; Function to find the base ID given an exception group name. Result is a function that -; maps the minor code into the Java expression for that minor code's actual value. -(define (get-base group-name) - (if (eqv? group-name 'OMG) - (lambda (minor-code) - (string-append "OMGVMCID.value + " (number->string minor-code))) - (let ; bind base-number outside the lambda so it is only evaluated once - ( - (base-number (get-sun-base-number group-name))) - (lambda (minor-code) - (string-append "SUNVMCID.value + " (number->string (+ base-number minor-code))))))) - -; Function to get a base value for the group-name -(define (get-sun-base-number group-name) - (let* - ( - (lst (list 'SUNBASE 'ORBUTIL 'ACTIVATION 'NAMING 'INTERCEPTORS 'POA 'IOR 'UTIL)) - (subsystem-size 200)) - (* subsystem-size (get-list-position group-name lst)))) - -; Function to get a 3 digit number for a system exception -(define (get-exception-id exception-name) - (let - ( - (lst (list 'UNKNOWN 'BAD_PARAM 'NO_MEMORY 'IMP_LIMIT 'COMM_FAILURE 'INV_OBJREF 'NO_PERMISSION - 'INTERNAL 'MARSHAL 'INITIALIZE 'NO_IMPLEMENT 'BAD_TYPECODE 'BAD_OPERATION 'NO_RESOURCES - 'NO_RESPONSE 'PERSIST_STORE 'BAD_INV_ORDER 'TRANSIENT 'FREE_MEM 'INV_IDENT 'INV_FLAG - 'INTF_REPOS 'BAD_CONTEXT 'OBJ_ADAPTER 'DATA_CONVERSION 'OBJECT_NOT_EXIST 'TRANSACTION_REQUIRED - 'TRANSACTION_ROLLEDBACK 'INVALID_TRANSACTION 'INV_POLICY 'CODESET_INCOMPATIBLE 'REBIND - 'TIMEOUT 'TRANSACTION_UNAVAILABLE 'BAD_QOS 'INVALID_ACTIVITY 'ACTIVITY_COMPLETED - 'ACTIVITY_REQUIRED ))) - (pad-number-string (get-list-position exception-name lst) 3))) - -; Return the message id string for any system exception -; -(define (get-message-id exception-type group-name minor) - (if (eqv? group-name 'OMG) - (get-standard-message-id exception-type minor) - (get-sun-message-id exception-type group-name minor))) - -; Return the message id string for a particular standard exception -; -(define (get-standard-message-id exception-type minor) - (string-append - "IOP" - (get-exception-id exception-type) - "0" - (pad-number-string (number->string minor) 4))) - -; Return the sun message id for this exception-type, group-name, and minor code. -(define (get-sun-message-id exception-type group-name minor) - (string-append - "IOP" - (get-exception-id exception-type) - "1" - (pad-number-string (+ (get-sun-base-number group-name) minor) 4))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; visitor framework for the input file format -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(define (visit-top obj func1) - (let* - ( - (package (car obj)) - (class (cadr obj)) - (group (caddr obj)) - (func2 (func1 package class group)) - (exceptions (cadddr obj))) - (visit-exceptions exceptions func2))) - -; visit the elements of an arbitrary list -; lst: the list to visit -; func: the function to apply to each element of lst -; next-level the function on lst element and func that visits the next level -(define (visit-list lst func next-level) - (if (null? (cdr lst)) - (next-level #t (car lst) func) - (begin - (next-level #f (car lst) func) - (visit-list (cdr lst) func next-level)))) - -(define (visit-exceptions exceptions func2) - (visit-list exceptions func2 (lambda (last-flag element func) (visit-exception last-flag element func)))) - -(define (visit-exception last-flag exception func2) - (let* - ( - (major (car exception)) - (minor-codes (cdr exception)) - (func3 (func2 last-flag major))) - (visit-minor-codes minor-codes func3))) - -(define (visit-minor-codes minor-codes func3) - (visit-list minor-codes func3 (lambda (last-flag element func) (visit-minor-code last-flag element func)))) - -(define (visit-minor-code last-flag minor-code func3) - (let* - ( - (name (car minor-code)) - (minor (cadr minor-code)) - (level (caddr minor-code)) - (msg (cadddr minor-code))) - (func3 last-flag name minor level msg))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; The visitors -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; A simple visitor that just echoes the input for test purposes -(define (simple-visitor package class group) - (let* - ( - (pw (IndentingPrintWriter. System.out$))) - (begin - (.indent pw) - (.printMsg pw "package=@ class=@ group=@" (list package class group)) - (.flush pw) - (lambda (last-flag major) - (begin - (.indent pw) - (.printMsg pw "major=@" (list major)) - (.flush pw) - (lambda (last-flag name minor level message) - (begin - (if last-flag (.undent pw)) - (.printMsg pw "name=@ minor=@ level=@ message=@" (list name minor level message)) - (.flush pw)))))))) - -; Function that returns a visitor that writes out the resource file in the form: -; id="MSGID: explanation" -; outdir: Output directory -(define (resource-visitor outdir) - (lambda (package class group) - (let* - ( - (file-name (string-append outdir java.io.File.separator$ class ".resource")) - (pw (IndentingPrintWriter. (FileOutputStream. file-name)))) - (begin - (dprint (string-append "package= " package " class=" class " group=" group " file-name=" file-name)) - (lambda (last-flag1 major) - (begin - ; (dprint (string-append "last-flag1=" last-flag1 " major=" major)) - (lambda (last-flag2 name minor level message) - (begin - ; (dprint (string-append "last-flag2=" last-flag2 " name=" name - ; " minor=" minor " level=" level " message=" message)) - (let* - ( - (msgid (get-message-id major group minor)) - (ident (StringUtil.toMixedCase (symbol->string name)))) - (begin - ; (dprint (string-append "msgid=" msgid " ident=" ident)) - (.printMsg pw "@.@=\"@: (@) @\"" (list group ident msgid major message)) - (.flush pw) - (if (and last-flag1 last-flag2) - (begin - ; (dprint "closing file") - (.close pw))))))))))))) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Top-level functions for creating the products. All have names of the form make-xxx -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; Read the minor codes from the infile and write out a resource file. -(define (make-resource infile outdir) - (tryCatch - (visit-top (read-file infile) (resource-visitor outdir)) - (lambda (exc) - (begin - (.println System.out$ (string-append "make-resource failed with exception " (.toString exc))) - (System.exit 1))))) - -; Read the minor codes from the infile and write a Java implementation to -; handle them to outfile under outdir -(define (make-class infile outdir) - (tryCatch - (write-class infile outdir (read-file infile)) - (lambda (exc) - (begin - (.println System.out$ (string-append "make-class failed with exception " (.toString exc))) - (System.exit 1))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; The original make-class implementation (this should be replaced by two visitors) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; Write out the Java source code for the StandardExceptions class -; outdir: Output directory to write the generated files -; obj: the data from the input file -(define (write-class infile outdir obj) - (let* - ( - (package-name (car obj)) - (class-name (cadr obj)) - (exception-group-name (caddr obj)) - (exceptions (cadddr obj)) - (file (FileOutputStream. (string-append outdir java.io.File.separator$ class-name ".java"))) - (pw (IndentingPrintWriter. file)) - ) - (begin - (write-class-header infile package-name class-name exception-group-name pw) - (.printMsg pw "package @ ;" - (list package-name)) - (.println pw) - (.println pw "import java.util.logging.Logger ;") - (.println pw "import java.util.logging.Level ;") - (.println pw) - (.println pw "import org.omg.CORBA.OMGVMCID ;") - (.println pw "import com.sun.corba.se.impl.util.SUNVMCID ;") - (.println pw "import org.omg.CORBA.CompletionStatus ;") - (.println pw "import org.omg.CORBA.SystemException ;") - (.println pw) - (.println pw "import com.sun.corba.se.spi.orb.ORB ;") - (.println pw) - (.println pw "import com.sun.corba.se.spi.logging.LogWrapperFactory;") - (.println pw) - (.println pw "import com.sun.corba.se.spi.logging.LogWrapperBase;") - (.println pw) - (write-imports exceptions pw) - (.println pw) - (.indent pw) - (.printMsg pw "public class @ extends LogWrapperBase {" - (list class-name)) - (.println pw) - (.printMsg pw "public @( Logger logger )" - (list class-name)) - (.indent pw) - (.println pw "{") - (.undent pw) - (.println pw "super( logger ) ;") - (.println pw "}") - (.println pw) - (.flush pw) - (write-factory-method class-name exception-group-name pw) - (write-exceptions exception-group-name exceptions (get-base exception-group-name) class-name pw) - (.undent pw) - (.println pw ) - (.println pw "}") - (.flush pw) - (.close pw) - ))) - -; Write out the header for the resource file -(define (write-class-header infile package class group pw) - (begin - (if (eqv? group 'OMG) - (.println pw "// Log wrapper class for standard exceptions") - (.printMsg pw "// Log wrapper class for Sun private system exceptions in group @" (list group))) - (.println pw "//") - (.printMsg pw "// Generated by mc.scm version @, DO NOT EDIT BY HAND!" (list version-string)) - (.printMsg pw "// Generated from input file @ on @" (list infile (java.util.Date.))) - (.println pw))) - -(define (write-factory-method class-name exception-group-name pw) - (begin - (.indent pw) - (.println pw "private static LogWrapperFactory factory = new LogWrapperFactory() {") - (.println pw "public LogWrapperBase create( Logger logger )" ) - (.indent pw) - (.println pw "{") - (.undent pw) - (.printMsg pw "return new @( logger ) ;" (list class-name)) - (.undent pw) - (.println pw "}" ) - (.println pw "} ;" ) - (.println pw) - (.printMsg pw "public static @ get( ORB orb, String logDomain )" (list class-name)) - (.indent pw) - (.println pw "{") - (.indent pw) - (.printMsg pw "@ wrapper = " - (list class-name)) - (.indent pw) - (.printMsg pw "(@) orb.getLogWrapper( logDomain, " - (list class-name)) - (.undent pw) - (.undent pw) - (.printMsg pw "\"@\", factory ) ;" - (list exception-group-name)) - (.undent pw) - (.println pw "return wrapper ;" ) - (.println pw "} " ) - (.println pw) - (.printMsg pw "public static @ get( String logDomain )" (list class-name)) - (.indent pw) - (.println pw "{") - (.indent pw) - (.printMsg pw "@ wrapper = " - (list class-name)) - (.indent pw) - (.printMsg pw "(@) ORB.staticGetLogWrapper( logDomain, " - (list class-name)) - (.undent pw) - (.undent pw) - (.printMsg pw "\"@\", factory ) ;" - (list exception-group-name)) - (.undent pw) - (.println pw "return wrapper ;" ) - (.println pw "} " ) - (.println pw))) - -; Write out the import list for the exceptions listed in obj -; obj: the data from the input file -; pw: an IndentingPrintWriter for the output file -(define (write-imports obj pw) - (if (null? obj) - () - (let - ( - (exception (caar obj)) - ) - (begin - (.print pw "import org.omg.CORBA.") - (.print pw exception) - (.println pw " ;") - (write-imports (cdr obj) pw) - )))) - -; Write out the list of exceptions starting with the first one -; obj: the data from the input file -; base: the lambda that returns the string defining the minor code value -; pw: an IndentingPrintWriter for the output file -(define (write-exceptions group-name obj base class-name pw) - (if (null? obj) - () - (let* - ( - (record (car obj)) - (exception (car record)) - (minor-codes (cdr record)) - ) - (begin - (write-exception group-name exception minor-codes base class-name pw) - (write-exceptions group-name (cdr obj) base class-name pw) - )))) - -; Write out a single exception -; exception: the CORBA SystemException type -; base: the base for the minor code value -; minor-codes: a list of minor code data for each minor exception type -; pw: an IndentingPrintWriter for the output file -(define (write-exception group-name exception minor-codes base class-name pw) - (begin - (.println pw "///////////////////////////////////////////////////////////") - (.printMsg pw "// @" (list exception)) - (.println pw "///////////////////////////////////////////////////////////") - (.println pw) - (write-methods group-name exception minor-codes base class-name pw) - (.flush pw))) - -; Write all of the methods for a single exception -; exception: the CORBA SystemException type -; base: the base for the minor code value -; minor-codes: a list of minor code data for each minor exception type -; pw: an IndentingPrintWriter for the output file -(define (write-methods group-name exception minor-codes base class-name pw) - (if (null? minor-codes) - () - (begin - (write-method group-name exception (car minor-codes) base class-name pw) - (write-methods group-name exception (cdr minor-codes) base class-name pw) - ))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Code that writes out the Java methods for exception handling -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; Write the methods for a single minor code within an exception -; exception: the CORBA SystemException type -; minor-code: minor code data for one minor exception type -; (name value level explanation) -; base: the base for the minor code value -; pw: an IndentingPrintWriter for the output file -(define (write-method group-name exception minor-code base class-name pw) - (let* - ( - (x (symbol->string (car minor-code))) - (ident (cons x (StringUtil.toMixedCase x))) - (value (cadr minor-code)) - (level (symbol->string (caddr minor-code))) - (explanation (cadddr minor-code)) - (num-params (StringUtil.countArgs explanation))) - (begin - (.printMsg pw "public static final int @ = @ ;" - (list x (base value))) - (.println pw ) - (.flush pw ) - (write-method-status-cause group-name exception ident level num-params class-name pw) - (.println pw) - (.flush pw) - (write-method-status exception ident level num-params pw) - (.println pw) - (.flush pw) - (write-method-cause exception ident level num-params pw) - (.println pw) - (.flush pw) - (write-method-no-args exception ident level num-params pw) - (.println pw) - (.flush pw)))) - -; Construct a string of the form arg1, ..., argn where n is num-params -(define (make-arg-string fixed leading-comma-flag num-args) - (let - ( - (helper (lambda (lcf n) - (let* - ( - (numstr (number->string (- n 1)))) - (if (or lcf (> n 1)) - (string-append ", " fixed numstr) - (string-append " " fixed numstr)))))) - (cond - ((eqv? num-args 0) " ") - ((eqv? num-args 1) (helper leading-comma-flag 1)) - (else (string-append - (make-arg-string fixed leading-comma-flag (- num-args 1)) - (helper leading-comma-flag num-args )))))) - -(define (make-decl-args leading-comma-flag num-args) - (make-arg-string "Object arg" leading-comma-flag num-args)) - -(define (make-call-args leading-comma-flag num-args) - (make-arg-string "arg" leading-comma-flag num-args)) - -; make-xxx-args patterns: -; leading-comma-flag #t -; -; 0 " " -; 1 ", arg0" -; 2 ", arg0, arg1" -; 3 ", arg0, arg1, arg2" -; -; 0 " " -; 1 ", Object arg0" -; 2 ", Object arg0, Object arg1" -; 3 ", Object arg0, Object arg1, Object arg2" -; -; leading-comma-flag #f -; -; 0 " " -; 1 " arg0" -; 2 " arg0, arg1" -; 3 " arg0, arg1, arg2" -; -; 0 " " -; 1 " Object arg0" -; 2 " Object arg0, Object arg1" -; 3 " Object arg0, Object arg1, Object arg2" - -(define (emit-assignments num pw) - (let - ( - (helper - (lambda (n) - (.printMsg pw "parameters[@] = arg@ ;" (list n n))))) - (if (= num 1) - (helper (- num 1)) - (begin - (emit-assignments (- num 1) pw) - (helper (- num 1)))))) - -; Write a method for an exception that takes a CompletionStatus and a cause -; exception: the CORBA system exception type -; id: the identifier for this exception in the form ( ident . mixed-case-ident ) -; level: the logging level -; num-params: number of parameters in the explanation string, which determines -; how many argn parameters we need -; pw: the indenting print writer we are using -(define (write-method-status-cause group-name exception id level num-params class-name pw) - (let* - ( - (ident (car id)) - (ident-mc (cdr id))) - (begin - (.indent pw) - (.printMsg pw "public @ @( CompletionStatus cs, Throwable t@) {" - (list exception ident-mc (make-decl-args #t num-params))) - (.printMsg pw "@ exc = new @( @, cs ) ;" - (list exception exception ident )) - - (.indent pw) - (.println pw "if (t != null)" ) - (.undent pw) - (.println pw "exc.initCause( t ) ;" ) - (.println pw) - - (.indent pw) - (.printMsg pw "if (logger.isLoggable( Level.@ )) {" - (list level)) - - (if (> num-params 0) - (begin - (.printMsg pw "Object[] parameters = new Object[@] ;" - (list (number->string num-params))) - (emit-assignments num-params pw) - ) - (begin - (.println pw "Object[] parameters = null ;" - ))) - - (.indent pw) - (.printMsg pw "doLog( Level.@, \"@.@\"," (list level group-name ident-mc)) - (.undent pw) - (.undent pw) - (.printMsg pw "parameters, @.class, exc ) ;" (list class-name)) - (.println pw "}") - (.println pw) - - (.undent pw) - (.println pw "return exc ;") - - (.println pw "}")))) - -; Write a method for an exception that takes a CompletionStatus. The cause is null. -; -; exception: the CORBA system exception type -; id: the identifier for this exception in the form ( ident . mixed-case-ident ) -; level: the logging level -; num-params: number of parameters in the explanation string, which determines -; how many argn parameters we need -; pw: the indenting print writer we are using -(define (write-method-status exception id level num-params pw) - (let* - ( - (ident-mc (cdr id))) - (begin - (.indent pw) - (.printMsg pw "public @ @( CompletionStatus cs@) {" - (list exception ident-mc (make-decl-args #t num-params))) - (.undent pw) - (.printMsg pw "return @( cs, null@ ) ;" - (list ident-mc (make-call-args #t num-params))) - (.println pw "}")))) - -; Write a method for an exception that takes a cause. The status is COMPLETED_NO. -; -; exception: the CORBA system exception type -; id: the identifier for this exception in the form ( ident . mixed-case-ident ) -; level: the logging level -; num-params: number of parameters in the explanation string, which determines -; how many argn parameters we need -; pw: the indenting print writer we are using -(define (write-method-cause exception id level num-params pw) - (let* - ( - (ident-mc (cdr id))) - (begin - (.indent pw) - (.printMsg pw "public @ @( Throwable t@) {" - (list exception ident-mc (make-decl-args #t num-params))) - (.undent pw) - (.printMsg pw "return @( CompletionStatus.COMPLETED_NO, t@ ) ;" - (list ident-mc (make-call-args #t num-params))) - (.println pw "}")))) - -; Write a method for an exception that takes no arguments. This is COMPLETED_NO and -; a null cause. -; -; exception: the CORBA system exception type -; id: the identifier for this exception in the form ( ident . mixed-case-ident ) -; level: the logging level -; num-params: number of parameters in the explanation string, which determines -; how many argn parameters we need -; pw: the indenting print writer we are using -(define (write-method-no-args exception id level num-params pw) - (let* - ( - (ident-mc (cdr id))) - (begin - (.indent pw) - (.printMsg pw "public @ @( @) {" - (list exception ident-mc (make-decl-args #f num-params))) - (.undent pw) - (.printMsg pw "return @( CompletionStatus.COMPLETED_NO, null@ ) ;" - (list ident-mc (make-call-args #t num-params))) - (.println pw "}")))) - -;;; end of file diff --git a/corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/run b/corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/run deleted file mode 100644 index 81efed3479a..00000000000 --- a/corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/run +++ /dev/null @@ -1,2 +0,0 @@ -#! /bin/sh -java -cp ${CLASSPATH}:lib/jscheme.jar:lib/util.jar jscheme.REPL mc.scm From 7c23bf37369efee6c51fd68aa24ecfea107bc424 Mon Sep 17 00:00:00 2001 From: Andrew John Hughes Date: Mon, 23 Mar 2009 17:43:53 -0700 Subject: [PATCH 42/75] 6695776: corba jscheme jar files in repository could be built from source Forward port of changes from the 6-open train. Reviewed-by: darcy, ohair, tbell --- jdk/THIRD_PARTY_README | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/jdk/THIRD_PARTY_README b/jdk/THIRD_PARTY_README index 9f4d7e5087a..690890548f2 100644 --- a/jdk/THIRD_PARTY_README +++ b/jdk/THIRD_PARTY_README @@ -61,6 +61,28 @@ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +%% This notice is provided with respect to littlecms, which may be included with this software: + +Little cms +Copyright (C) 1998-2004 Marti Maria + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. %% This notice is provided with respect to zlib 1.1.3, which may be included with this software: Acknowledgments: @@ -115,16 +137,6 @@ COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQ The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the software without specific, written prior permission. Title to copyright in this software and any associated documentation will at all times remain with copyright holders. ____________________________________ This formulation of W3C's notice and license became active on August 14 1998 so as to improve compatibility with GPL. This version ensures that W3C software licensing terms are no more restrictive than GPL and consequently W3C software may be distributed in GPL packages. See the older formulation for the policy prior to this date. Please see our Copyright FAQ for common questions about using materials from our site, including specific terms and conditions for packages like libwww, Amaya, and Jigsaw. Other questions about this notice can be directed to site-policy@w3.org. -  -%% This notice is provided with respect to jscheme.jar, which may be included with this software: -Software License Agreement -Copyright © 1998-2002 by Peter Norvig. -Permission is granted to anyone to use this software, in source or object code form, on any computer system, and to modify, compile, decompile, run, and redistribute it to anyone else, subject to the following restrictions: -1.The author makes no warranty of any kind, either expressed or implied, about the suitability of this software for any purpose. -2.The author accepts no liability of any kind for damages or other consequences of the use of this software, even if they arise from defects in the software. -3.The origin of this software must not be misrepresented, either by explicit claim or by omission. -4.Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. Altered versions may be distributed in packages under other licenses (such as the GNU license). -If you find this software useful, it would be nice if you let me (peter@norvig.com) know about it, and nicer still if you send me modifications that you are willing to share. However, you are not required to do so. %% This notice is provided with respect to PC/SC Lite for Suse Linux v. 1.1.1, which may be included with this software: From 312ee333acdc5cabd6493f7c91e80ff0163e3f84 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Tue, 24 Mar 2009 09:14:02 -0700 Subject: [PATCH 43/75] 6821031: Upgrade OpenJDK's LittleCMS version to 1.18 Reviewed-by: bae, igor --- .../share/native/sun/java2d/cmm/lcms/LCMS.c | 8 +- .../native/sun/java2d/cmm/lcms/cmscam02.c | 23 +- .../native/sun/java2d/cmm/lcms/cmscam97.c | 8 +- .../native/sun/java2d/cmm/lcms/cmscgats.c | 790 +++++++++++---- .../native/sun/java2d/cmm/lcms/cmscnvrt.c | 7 +- .../share/native/sun/java2d/cmm/lcms/cmserr.c | 9 +- .../native/sun/java2d/cmm/lcms/cmsgamma.c | 47 +- .../share/native/sun/java2d/cmm/lcms/cmsgmt.c | 38 +- .../native/sun/java2d/cmm/lcms/cmsintrp.c | 21 +- .../share/native/sun/java2d/cmm/lcms/cmsio0.c | 130 ++- .../share/native/sun/java2d/cmm/lcms/cmsio1.c | 938 ++++++++++-------- .../share/native/sun/java2d/cmm/lcms/cmslut.c | 112 ++- .../native/sun/java2d/cmm/lcms/cmsmatsh.c | 29 +- .../native/sun/java2d/cmm/lcms/cmsmtrx.c | 46 +- .../native/sun/java2d/cmm/lcms/cmsnamed.c | 24 +- .../native/sun/java2d/cmm/lcms/cmspack.c | 113 ++- .../share/native/sun/java2d/cmm/lcms/cmspcs.c | 6 +- .../share/native/sun/java2d/cmm/lcms/cmsps2.c | 141 +-- .../native/sun/java2d/cmm/lcms/cmssamp.c | 47 +- .../native/sun/java2d/cmm/lcms/cmsvirt.c | 52 +- .../native/sun/java2d/cmm/lcms/cmswtpnt.c | 54 +- .../native/sun/java2d/cmm/lcms/cmsxform.c | 127 ++- .../share/native/sun/java2d/cmm/lcms/icc34.h | 5 + .../share/native/sun/java2d/cmm/lcms/lcms.h | 380 +++---- 24 files changed, 1962 insertions(+), 1193 deletions(-) diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c b/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c index 404ab2e686d..42a5cc23f30 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c @@ -374,6 +374,10 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagData return; } +// Modify data for a tag in a profile +LCMSBOOL LCMSEXPORT _cmsModifyTagData(cmsHPROFILE hProfile, + icTagSignature sig, void *data, size_t size); + /* * Class: sun_java2d_cmm_lcms_LCMS * Method: setTagData @@ -561,10 +565,10 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_initLCMS PF_ID_fID = (*env)->GetFieldID (env, Pf, "ID", "J"); } -BOOL _cmsModifyTagData(cmsHPROFILE hProfile, icTagSignature sig, +LCMSBOOL _cmsModifyTagData(cmsHPROFILE hProfile, icTagSignature sig, void *data, size_t size) { - BOOL isNew; + LCMSBOOL isNew; int i, idx, delta, count; LPBYTE padChars[3] = {0, 0, 0}; LPBYTE beforeBuf, afterBuf, ptr; diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c index 9aa971cb878..c560470c499 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -51,7 +51,7 @@ -// CIECAM 02 appearance model +// CIECAM 02 appearance model. Many thanks to Jordi Vilar for the debugging. #include "lcms.h" @@ -196,6 +196,10 @@ CAM02COLOR NonlinearCompression(CAM02COLOR clr, LPcmsCIECAM02 pMod) clr.RGBpa[i] = (400.0 * temp) / (temp + 27.13) + 0.1; } } + + clr.A = (((2.0 * clr.RGBpa[0]) + clr.RGBpa[1] + + (clr.RGBpa[2] / 20.0)) - 0.305) * pMod->Nbb; + return clr; } @@ -249,9 +253,6 @@ CAM02COLOR ComputeCorrelates(CAM02COLOR clr, LPcmsCIECAM02 pMod) clr.H = 300 + ((100*((clr.h - 237.53)/1.2)) / temp); } - clr.A = (((2.0 * clr.RGBpa[0]) + clr.RGBpa[1] + - (clr.RGBpa[2] / 20.0)) - 0.305) * pMod->Nbb; - clr.J = 100.0 * pow((clr.A / pMod->adoptedWhite.A), (pMod->c * pMod->z)); @@ -395,7 +396,7 @@ LCMSHANDLE LCMSEXPORT cmsCIECAM02Init(LPcmsViewingConditions pVC) LPcmsCIECAM02 lpMod; - if((lpMod = (LPcmsCIECAM02) malloc(sizeof(cmsCIECAM02))) == NULL) { + if((lpMod = (LPcmsCIECAM02) _cmsMalloc(sizeof(cmsCIECAM02))) == NULL) { return (LCMSHANDLE) NULL; } @@ -449,14 +450,19 @@ LCMSHANDLE LCMSEXPORT cmsCIECAM02Init(LPcmsViewingConditions pVC) lpMod -> z = compute_z(lpMod); lpMod -> Nbb = computeNbb(lpMod); lpMod -> FL = computeFL(lpMod); + + if (lpMod -> D == D_CALCULATE || + lpMod -> D == D_CALCULATE_DISCOUNT) { + lpMod -> D = computeD(lpMod); + } + lpMod -> Ncb = lpMod -> Nbb; lpMod -> adoptedWhite = XYZtoCAT02(lpMod -> adoptedWhite); lpMod -> adoptedWhite = ChromaticAdaptation(lpMod -> adoptedWhite, lpMod); lpMod -> adoptedWhite = CAT02toHPE(lpMod -> adoptedWhite); lpMod -> adoptedWhite = NonlinearCompression(lpMod -> adoptedWhite, lpMod); - lpMod -> adoptedWhite = ComputeCorrelates(lpMod -> adoptedWhite, lpMod); return (LCMSHANDLE) lpMod; @@ -465,7 +471,7 @@ LCMSHANDLE LCMSEXPORT cmsCIECAM02Init(LPcmsViewingConditions pVC) void LCMSEXPORT cmsCIECAM02Done(LCMSHANDLE hModel) { LPcmsCIECAM02 lpMod = (LPcmsCIECAM02) (LPSTR) hModel; - if (lpMod) free(lpMod); + if (lpMod) _cmsFree(lpMod); } @@ -510,3 +516,4 @@ void LCMSEXPORT cmsCIECAM02Reverse(LCMSHANDLE hModel, LPcmsJCh pIn, LPcmsCIEXYZ pOut ->Z = clr.XYZ[2]; } + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam97.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam97.c index a49a3e6dc0e..5c70ff458b7 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam97.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam97.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -174,7 +174,7 @@ typedef struct { LCMSAPI void LCMSEXPORT cmsCIECAM97sDone(LCMSHANDLE hModel) { LPcmsCIECAM97s lpMod = (LPcmsCIECAM97s) (LPSTR) hModel; - if (lpMod) free(lpMod); + if (lpMod) _cmsFree(lpMod); } // Partial discounting for adaptation degree computation @@ -331,7 +331,7 @@ LCMSAPI LCMSHANDLE LCMSEXPORT cmsCIECAM97sInit(LPcmsViewingConditions pVC) LPcmsCIECAM97s lpMod; VEC3 tmp; - if((lpMod = (LPcmsCIECAM97s) malloc(sizeof(cmsCIECAM97s))) == NULL) { + if((lpMod = (LPcmsCIECAM97s) _cmsMalloc(sizeof(cmsCIECAM97s))) == NULL) { return (LCMSHANDLE) NULL; } @@ -449,7 +449,7 @@ LCMSAPI LCMSHANDLE LCMSEXPORT cmsCIECAM97sInit(LPcmsViewingConditions pVC) // RGB_subw = [MlamRigg][WP/YWp] #ifdef USE_CIECAM97s2 - MAT3eval(&lpMod -> RGB_subw, &lpMod -> MlamRigg, (LPVEC3) &lpMod -> WP); + MAT3eval(&lpMod -> RGB_subw, &lpMod -> MlamRigg, &lpMod -> WP); #else VEC3divK(&tmp, (LPVEC3) &lpMod -> WP, lpMod->WP.Y); MAT3eval(&lpMod -> RGB_subw, &lpMod -> MlamRigg, &tmp); diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c index 2b486437a77..9f26b854476 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -65,22 +65,25 @@ LCMSAPI int LCMSEXPORT cmsIT8SetTable(LCMSHANDLE IT8, int nTable); // Persistence LCMSAPI LCMSHANDLE LCMSEXPORT cmsIT8LoadFromFile(const char* cFileName); LCMSAPI LCMSHANDLE LCMSEXPORT cmsIT8LoadFromMem(void *Ptr, size_t len); -LCMSAPI BOOL LCMSEXPORT cmsIT8SaveToFile(LCMSHANDLE IT8, const char* cFileName); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SaveToFile(LCMSHANDLE IT8, const char* cFileName); // Properties LCMSAPI const char* LCMSEXPORT cmsIT8GetSheetType(LCMSHANDLE hIT8); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetSheetType(LCMSHANDLE hIT8, const char* Type); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetSheetType(LCMSHANDLE hIT8, const char* Type); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetComment(LCMSHANDLE hIT8, const char* cComment); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetComment(LCMSHANDLE hIT8, const char* cComment); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetPropertyStr(LCMSHANDLE hIT8, const char* cProp, const char *Str); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetPropertyDbl(LCMSHANDLE hIT8, const char* cProp, double Val); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetPropertyHex(LCMSHANDLE hIT8, const char* cProp, int Val); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetPropertyUncooked(LCMSHANDLE hIT8, const char* Key, const char* Buffer); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyStr(LCMSHANDLE hIT8, const char* cProp, const char *Str); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyDbl(LCMSHANDLE hIT8, const char* cProp, double Val); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyHex(LCMSHANDLE hIT8, const char* cProp, int Val); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyMulti(LCMSHANDLE hIT8, const char* cProp, const char* cSubProp, const char *Val); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyUncooked(LCMSHANDLE hIT8, const char* Key, const char* Buffer); LCMSAPI const char* LCMSEXPORT cmsIT8GetProperty(LCMSHANDLE hIT8, const char* cProp); LCMSAPI double LCMSEXPORT cmsIT8GetPropertyDbl(LCMSHANDLE hIT8, const char* cProp); -LCMSAPI int LCMSEXPORT cmsIT8EnumProperties(LCMSHANDLE IT8, char ***PropertyNames); +LCMSAPI const char* LCMSEXPORT cmsIT8GetPropertyMulti(LCMSHANDLE hIT8, const char* cProp, const char *cSubProp); +LCMSAPI int LCMSEXPORT cmsIT8EnumProperties(LCMSHANDLE IT8, const char ***PropertyNames); +LCMSAPI int LCMSEXPORT cmsIT8EnumPropertyMulti(LCMSHANDLE hIT8, const char* cProp, const char*** SubpropertyNames); // Datasets @@ -89,10 +92,10 @@ LCMSAPI const char* LCMSEXPORT cmsIT8GetPatchName(LCMSHANDLE hIT8, int nPatc LCMSAPI const char* LCMSEXPORT cmsIT8GetDataRowCol(LCMSHANDLE IT8, int row, int col); LCMSAPI double LCMSEXPORT cmsIT8GetDataRowColDbl(LCMSHANDLE IT8, int col, int row); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetDataRowCol(LCMSHANDLE hIT8, int row, int col, +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetDataRowCol(LCMSHANDLE hIT8, int row, int col, const char* Val); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetDataRowColDbl(LCMSHANDLE hIT8, int row, int col, +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetDataRowColDbl(LCMSHANDLE hIT8, int row, int col, double Val); LCMSAPI const char* LCMSEXPORT cmsIT8GetData(LCMSHANDLE IT8, const char* cPatch, const char* cSample); @@ -100,15 +103,15 @@ LCMSAPI const char* LCMSEXPORT cmsIT8GetData(LCMSHANDLE IT8, const char* cPa LCMSAPI double LCMSEXPORT cmsIT8GetDataDbl(LCMSHANDLE IT8, const char* cPatch, const char* cSample); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetData(LCMSHANDLE IT8, const char* cPatch, +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetData(LCMSHANDLE IT8, const char* cPatch, const char* cSample, const char *Val); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetDataDbl(LCMSHANDLE hIT8, const char* cPatch, +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetDataDbl(LCMSHANDLE hIT8, const char* cPatch, const char* cSample, double Val); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetDataFormat(LCMSHANDLE IT8, int n, const char *Sample); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetDataFormat(LCMSHANDLE IT8, int n, const char *Sample); LCMSAPI int LCMSEXPORT cmsIT8EnumDataFormat(LCMSHANDLE IT8, char ***SampleNames); LCMSAPI void LCMSEXPORT cmsIT8DefineDblFormat(LCMSHANDLE IT8, const char* Formatter); @@ -126,7 +129,7 @@ LCMSAPI int LCMSEXPORT cmsIT8SetTableByLabel(LCMSHANDLE hIT8, const // #define STRICT_CGATS 1 #define MAXID 128 // Max lenght of identifier -#define MAXSTR 255 // Max lenght of string +#define MAXSTR 1024 // Max lenght of string #define MAXTABLES 255 // Max Number of tables in a single stream #define MAXINCLUDE 20 // Max number of nested includes @@ -137,6 +140,9 @@ LCMSAPI int LCMSEXPORT cmsIT8SetTableByLabel(LCMSHANDLE hIT8, const #ifndef NON_WINDOWS #include +#define DIR_CHAR '\\' +#else +#define DIR_CHAR '/' #endif // Symbols @@ -160,6 +166,7 @@ typedef enum { SEND_DATA, SEND_DATA_FORMAT, SKEYWORD, + SDATA_FORMAT_ID, SINCLUDE } SYMBOL; @@ -171,7 +178,8 @@ typedef enum { WRITE_UNCOOKED, WRITE_STRINGIFY, WRITE_HEXADECIMAL, - WRITE_BINARY + WRITE_BINARY, + WRITE_PAIR } WRITEMODE; @@ -181,6 +189,8 @@ typedef struct _KeyVal { struct _KeyVal* Next; char* Keyword; // Name of variable + struct _KeyVal* NextSubkey; // If key is a dictionary, points to the next item + char* Subkey; // If key is a dictionary, points to the subkey name char* Value; // Points to value WRITEMODE WriteAs; // How to write the value @@ -220,7 +230,12 @@ typedef struct _Table { } TABLE, *LPTABLE; +// File stream being parsed +typedef struct _FileContext { + char FileName[MAX_PATH]; // File name if being readed from file + FILE* Stream; // File stream or NULL if holded in memory + } FILECTX, *LPFILECTX; // This struct hold all information about an openened // IT8 handler. Only one dataset is allowed. @@ -257,9 +272,9 @@ typedef struct { char* Source; // Points to loc. being parsed int lineno; // line counter for error reporting - char FileName[MAX_PATH]; // File name if being readed from file - FILE* Stream[MAXINCLUDE]; // File stream or NULL if holded in memory + LPFILECTX FileStack[MAXINCLUDE]; // Stack of files being parsed int IncludeSP; // Include Stack Pointer + char* MemoryBlock; // The stream if holded in memory char DoubleFormatter[MAXID]; // Printf-like 'double' formatter @@ -270,14 +285,14 @@ typedef struct { typedef struct { - FILE* stream; // For save-to-file behaviour + FILE* stream; // For save-to-file behaviour - LPBYTE Base; - LPBYTE Ptr; // For save-to-mem behaviour - size_t Used; - size_t Max; + LPBYTE Base; + LPBYTE Ptr; // For save-to-mem behaviour + size_t Used; + size_t Max; - } SAVESTREAM, FAR* LPSAVESTREAM; + } SAVESTREAM, FAR* LPSAVESTREAM; // ------------------------------------------------------ IT8 parsing routines @@ -298,59 +313,104 @@ static const KEYWORD TabKeys[] = { {".INCLUDE", SINCLUDE}, {"BEGIN_DATA", SBEGIN_DATA }, {"BEGIN_DATA_FORMAT", SBEGIN_DATA_FORMAT }, + {"DATA_FORMAT_IDENTIFIER", SDATA_FORMAT_ID}, {"END_DATA", SEND_DATA}, {"END_DATA_FORMAT", SEND_DATA_FORMAT}, {"KEYWORD", SKEYWORD} - }; #define NUMKEYS (sizeof(TabKeys)/sizeof(KEYWORD)) // Predefined properties -static const char* PredefinedProperties[] = { +// A property +typedef struct { + const char *id; + WRITEMODE as; + } PROPERTY; - "NUMBER_OF_FIELDS", // Required - NUMBER OF FIELDS - "NUMBER_OF_SETS", // Required - NUMBER OF SETS - "ORIGINATOR", // Required - Identifies the specific system, organization or individual that created the data file. - "FILE_DESCRIPTOR", // Required - Describes the purpose or contents of the data file. - "CREATED", // Required - Indicates date of creation of the data file. - "DESCRIPTOR", // Required - Describes the purpose or contents of the data file. - "DIFFUSE_GEOMETRY", // The diffuse geometry used. Allowed values are "sphere" or "opal". - "MANUFACTURER", - "MANUFACTURE", // Some broken Fuji targets does store this value - "PROD_DATE", // Identifies year and month of production of the target in the form yyyy:mm. - "SERIAL", // Uniquely identifies individual physical target. +static PROPERTY PredefinedProperties[] = { - "MATERIAL", // Identifies the material on which the target was produced using a code + {"NUMBER_OF_FIELDS", WRITE_UNCOOKED}, // Required - NUMBER OF FIELDS + {"NUMBER_OF_SETS", WRITE_UNCOOKED}, // Required - NUMBER OF SETS + {"ORIGINATOR", WRITE_STRINGIFY}, // Required - Identifies the specific system, organization or individual that created the data file. + {"FILE_DESCRIPTOR", WRITE_STRINGIFY}, // Required - Describes the purpose or contents of the data file. + {"CREATED", WRITE_STRINGIFY}, // Required - Indicates date of creation of the data file. + {"DESCRIPTOR", WRITE_STRINGIFY}, // Required - Describes the purpose or contents of the data file. + {"DIFFUSE_GEOMETRY", WRITE_STRINGIFY}, // The diffuse geometry used. Allowed values are "sphere" or "opal". + {"MANUFACTURER", WRITE_STRINGIFY}, + {"MANUFACTURE", WRITE_STRINGIFY}, // Some broken Fuji targets does store this value + {"PROD_DATE", WRITE_STRINGIFY}, // Identifies year and month of production of the target in the form yyyy:mm. + {"SERIAL", WRITE_STRINGIFY}, // Uniquely identifies individual physical target. + + {"MATERIAL", WRITE_STRINGIFY}, // Identifies the material on which the target was produced using a code // uniquely identifying th e material. This is intend ed to be used for IT8.7 // physical targets only (i.e . IT8.7/1 a nd IT8.7/2). - "INSTRUMENTATION", // Used to report the specific instrumentation used (manufacturer and + {"INSTRUMENTATION", WRITE_STRINGIFY}, // Used to report the specific instrumentation used (manufacturer and // model number) to generate the data reported. This data will often // provide more information about the particular data collected than an // extensive list of specific details. This is particularly important for // spectral data or data derived from spectrophotometry. - "MEASUREMENT_SOURCE", // Illumination used for spectral measurements. This data helps provide + {"MEASUREMENT_SOURCE", WRITE_STRINGIFY}, // Illumination used for spectral measurements. This data helps provide // a guide to the potential for issues of paper fluorescence, etc. - "PRINT_CONDITIONS", // Used to define the characteristics of the printed sheet being reported. + {"PRINT_CONDITIONS", WRITE_STRINGIFY}, // Used to define the characteristics of the printed sheet being reported. // Where standard conditions have been defined (e.g., SWOP at nominal) // named conditions may suffice. Otherwise, detailed information is // needed. - "SAMPLE_BACKING", // Identifies the backing material used behind the sample during - // measurement. Allowed values are “black”, “white”, or "na". + {"SAMPLE_BACKING", WRITE_STRINGIFY}, // Identifies the backing material used behind the sample during + // measurement. Allowed values are “black”, “white”, or {"na". - "CHISQ_DOF" // Degrees of freedom associated with the Chi squared statistic + {"CHISQ_DOF", WRITE_STRINGIFY}, // Degrees of freedom associated with the Chi squared statistic + +// new in recent specs: + {"MEASUREMENT_GEOMETRY", WRITE_STRINGIFY}, // The type of measurement, either reflection or transmission, should be indicated + // along with details of the geometry and the aperture size and shape. For example, + // for transmission measurements it is important to identify 0/diffuse, diffuse/0, + // opal or integrating sphere, etc. For reflection it is important to identify 0/45, + // 45/0, sphere (specular included or excluded), etc. + + {"FILTER", WRITE_STRINGIFY}, // Identifies the use of physical filter(s) during measurement. Typically used to + // denote the use of filters such as none, D65, Red, Green or Blue. + + {"POLARIZATION", WRITE_STRINGIFY}, // Identifies the use of a physical polarization filter during measurement. Allowed + // values are {"yes”, “white”, “none” or “na”. + + {"WEIGHTING_FUNCTION", WRITE_PAIR}, // Indicates such functions as: the CIE standard observer functions used in the + // calculation of various data parameters (2 degree and 10 degree), CIE standard + // illuminant functions used in the calculation of various data parameters (e.g., D50, + // D65, etc.), density status response, etc. If used there shall be at least one + // name-value pair following the WEIGHTING_FUNCTION tag/keyword. The first attribute + // in the set shall be {"name" and shall identify the particular parameter used. + // The second shall be {"value" and shall provide the value associated with that name. + // For ASCII data, a string containing the Name and Value attribute pairs shall follow + // the weighting function keyword. A semi-colon separates attribute pairs from each + // other and within the attribute the name and value are separated by a comma. + + {"COMPUTATIONAL_PARAMETER", WRITE_PAIR}, // Parameter that is used in computing a value from measured data. Name is the name + // of the calculation, parameter is the name of the parameter used in the calculation + // and value is the value of the parameter. + + {"TARGET_TYPE", WRITE_STRINGIFY}, // The type of target being measured, e.g. IT8.7/1, IT8.7/3, user defined, etc. + + {"COLORANT", WRITE_STRINGIFY}, // Identifies the colorant(s) used in creating the target. + + {"TABLE_DESCRIPTOR", WRITE_STRINGIFY}, // Describes the purpose or contents of a data table. + + {"TABLE_NAME", WRITE_STRINGIFY} // Provides a short name for a data table. }; -#define NUMPREDEFINEDPROPS (sizeof(PredefinedProperties)/sizeof(char *)) +#define NUMPREDEFINEDPROPS (sizeof(PredefinedProperties)/sizeof(PROPERTY)) // Predefined sample types on dataset static const char* PredefinedSampleID[] = { + "SAMPLE_ID", // Identifies sample that data represents + "STRING", // Identifies label, or other non-machine readable value. + // Value must begin and end with a " symbol "CMYK_C", // Cyan component of CMYK data expressed as a percentage "CMYK_M", // Magenta component of CMYK data expressed as a percentage @@ -378,7 +438,7 @@ static const char* PredefinedSampleID[] = { "LAB_B", // b* component of Lab data "LAB_C", // C*ab component of Lab data "LAB_H", // hab component of Lab data - "LAB_DE" // CIE dE + "LAB_DE", // CIE dE "LAB_DE_94", // CIE dE using CIE 94 "LAB_DE_CMC", // dE using CMC "LAB_DE_2000", // CIE dE using CIE DE 2000 @@ -388,7 +448,7 @@ static const char* PredefinedSampleID[] = { "STDEV_Y", // Standard deviation of Y (tristimulus data) "STDEV_Z", // Standard deviation of Z (tristimulus data) "STDEV_L", // Standard deviation of L* - "STDEV_A" // Standard deviation of a* + "STDEV_A", // Standard deviation of a* "STDEV_B", // Standard deviation of b* "STDEV_DE", // Standard deviation of CIE dE "CHI_SQD_PAR"}; // The average of the standard deviations of L*, a* and b*. It is @@ -397,57 +457,120 @@ static const char* PredefinedSampleID[] = { #define NUMPREDEFINEDSAMPLEID (sizeof(PredefinedSampleID)/sizeof(char *)) +//Forward declaration of some internal functions +static +void* AllocChunk(LPIT8 it8, size_t size); + // Checks if c is a separator static -BOOL isseparator(int c) +LCMSBOOL isseparator(int c) { return (c == ' ') || (c == '\t') || (c == '\r'); } // Checks whatever if c is a valid identifier char - static -BOOL ismiddle(int c) +LCMSBOOL ismiddle(int c) { return (!isseparator(c) && (c != '#') && (c !='\"') && (c != '\'') && (c > 32) && (c < 127)); } // Checks whatsever if c is a valid identifier middle char. static -BOOL isidchar(int c) +LCMSBOOL isidchar(int c) { return isalnum(c) || ismiddle(c); } // Checks whatsever if c is a valid identifier first char. static -BOOL isfirstidchar(int c) +LCMSBOOL isfirstidchar(int c) { return !isdigit(c) && ismiddle(c); } +// checks whether the supplied path looks like an absolute path +// NOTE: this function doesn't checks if the path exists or even if it's legal +static +LCMSBOOL isabsolutepath(const char *path) +{ + if(path == NULL) + return FALSE; + + if(path[0] == DIR_CHAR) + return TRUE; + +#ifndef NON_WINDOWS + if(isalpha(path[0]) && path[1] == ':') + return TRUE; +#endif + return FALSE; +} + +// Makes a file path based on a given reference path +// NOTE: buffer is assumed to point to at least MAX_PATH bytes +// NOTE: both relPath and basePath are assumed to be no more than MAX_PATH characters long (including the null terminator!) +// NOTE: this function doesn't check if the path exists or even if it's legal +static +LCMSBOOL _cmsMakePath(const char *relPath, const char *basePath, char *buffer) +{ + if (!isabsolutepath(relPath)) { + + char *tail; + + strncpy(buffer, basePath, MAX_PATH-1); + tail = strrchr(buffer, DIR_CHAR); + if (tail != NULL) { + + size_t len = tail - buffer; + strncpy(tail + 1, relPath, MAX_PATH - len -1); + // TODO: if combined path is longer than MAX_PATH, this should return FALSE! + return TRUE; + } + } + strncpy(buffer, relPath, MAX_PATH - 1); + buffer[MAX_PATH-1] = 0; + return TRUE; +} + + +// Make sure no exploit is being even tried static -BOOL SynError(LPIT8 it8, const char *Txt, ...) +const char* NoMeta(const char* str) +{ + if (strchr(str, '%') != NULL) + return "**** CORRUPTED FORMAT STRING ***"; + + return str; +} + + +// Syntax error +static +LCMSBOOL SynError(LPIT8 it8, const char *Txt, ...) { char Buffer[256], ErrMsg[1024]; va_list args; va_start(args, Txt); - vsprintf(Buffer, Txt, args); + vsnprintf(Buffer, 255, Txt, args); + Buffer[255] = 0; va_end(args); - sprintf(ErrMsg, "%s: Line %d, %s", it8->FileName, it8->lineno, Buffer); + snprintf(ErrMsg, 1023, "%s: Line %d, %s", it8->FileStack[it8 ->IncludeSP]->FileName, it8->lineno, Buffer); + ErrMsg[1023] = 0; it8->sy = SSYNERROR; - cmsSignalError(LCMS_ERRC_ABORTED, ErrMsg); + cmsSignalError(LCMS_ERRC_ABORTED, "%s", ErrMsg); return FALSE; } +// Check if current symbol is same as specified. issue an error else. static -BOOL Check(LPIT8 it8, SYMBOL sy, const char* Err) +LCMSBOOL Check(LPIT8 it8, SYMBOL sy, const char* Err) { if (it8 -> sy != sy) - return SynError(it8, Err); + return SynError(it8, NoMeta(Err)); return TRUE; } @@ -457,15 +580,15 @@ BOOL Check(LPIT8 it8, SYMBOL sy, const char* Err) static void NextCh(LPIT8 it8) { - if (it8 -> Stream[it8 ->IncludeSP]) { + if (it8 -> FileStack[it8 ->IncludeSP]->Stream) { - it8 ->ch = fgetc(it8 ->Stream[it8 ->IncludeSP]); + it8 ->ch = fgetc(it8 ->FileStack[it8 ->IncludeSP]->Stream); - if (feof(it8 -> Stream[it8 ->IncludeSP])) { + if (feof(it8 -> FileStack[it8 ->IncludeSP]->Stream)) { if (it8 ->IncludeSP > 0) { - fclose(it8 ->Stream[it8->IncludeSP--]); + fclose(it8 ->FileStack[it8->IncludeSP--]->Stream); it8 -> ch = ' '; // Whitespace to be ignored } else @@ -476,7 +599,6 @@ void NextCh(LPIT8 it8) } else { - it8->ch = *it8->Source; if (it8->ch) it8->Source++; } @@ -799,18 +921,39 @@ void InSymbol(LPIT8 it8) if (it8 -> sy == SINCLUDE) { - FILE* IncludeFile; + LPFILECTX FileNest; + + if(it8 -> IncludeSP >= (MAXINCLUDE-1)) + { + SynError(it8, "Too many recursion levels"); + return; + } InSymbol(it8); if (!Check(it8, SSTRING, "Filename expected")) return; - IncludeFile = fopen(it8 -> str, "rt"); - if (IncludeFile == NULL) { - SynError(it8, "File %s not found", it8 ->str); - return; + FileNest = it8 -> FileStack[it8 -> IncludeSP + 1]; + if(FileNest == NULL) + { + FileNest = it8 ->FileStack[it8 -> IncludeSP + 1] = (LPFILECTX)AllocChunk(it8, sizeof(FILECTX)); + //if(FileNest == NULL) + // TODO: how to manage out-of-memory conditions? } - it8 -> Stream[++it8 -> IncludeSP] = IncludeFile; + if(_cmsMakePath(it8->str, it8->FileStack[it8->IncludeSP]->FileName, FileNest->FileName) == FALSE) + { + SynError(it8, "File path too long"); + return; + } + + FileNest->Stream = fopen(FileNest->FileName, "rt"); + if (FileNest->Stream == NULL) { + + SynError(it8, "File %s not found", FileNest->FileName); + return; + } + it8->IncludeSP++; + it8 ->ch = ' '; InSymbol(it8); } @@ -819,7 +962,7 @@ void InSymbol(LPIT8 it8) // Checks end of line separator static -BOOL CheckEOLN(LPIT8 it8) +LCMSBOOL CheckEOLN(LPIT8 it8) { if (!Check(it8, SEOLN, "Expected separator")) return FALSE; while (it8 -> sy == SEOLN) @@ -850,21 +993,26 @@ void SkipEOLN(LPIT8 it8) // Returns a string holding current value static -BOOL GetVal(LPIT8 it8, char* Buffer, const char* ErrorTitle) +LCMSBOOL GetVal(LPIT8 it8, char* Buffer, size_t max, const char* ErrorTitle) { switch (it8->sy) { - case SIDENT: strncpy(Buffer, it8->id, MAXID-1); break; - case SINUM: sprintf(Buffer, "%d", it8 -> inum); break; - case SDNUM: sprintf(Buffer, it8->DoubleFormatter, it8 -> dnum); break; - case SSTRING: strncpy(Buffer, it8->str, MAXSTR-1); break; + case SIDENT: strncpy(Buffer, it8->id, max); + Buffer[max-1]=0; + break; + case SINUM: snprintf(Buffer, max, "%d", it8 -> inum); break; + case SDNUM: snprintf(Buffer, max, it8->DoubleFormatter, it8 -> dnum); break; + case SSTRING: strncpy(Buffer, it8->str, max); + Buffer[max-1] = 0; + break; default: - return SynError(it8, ErrorTitle); + return SynError(it8, "%s", ErrorTitle); } - return TRUE; + Buffer[max] = 0; + return TRUE; } // ---------------------------------------------------------- Table @@ -872,7 +1020,13 @@ BOOL GetVal(LPIT8 it8, char* Buffer, const char* ErrorTitle) static LPTABLE GetTable(LPIT8 it8) { - return it8 ->Tab + it8 ->nTable; + if ((it8 -> nTable >= it8 ->TablesCount) || (it8 -> nTable < 0)) { + + SynError(it8, "Table %d out of sequence", it8 -> nTable); + return it8 -> Tab; + } + + return it8 ->Tab + it8 ->nTable; } // ---------------------------------------------------------- Memory management @@ -896,15 +1050,15 @@ void LCMSEXPORT cmsIT8Free(LCMSHANDLE hIT8) for (p = it8->MemorySink; p != NULL; p = n) { n = p->Next; - if (p->Ptr) free(p->Ptr); - free(p); + if (p->Ptr) _cmsFree(p->Ptr); + _cmsFree(p); } } if (it8->MemoryBlock) - free(it8->MemoryBlock); + _cmsFree(it8->MemoryBlock); - free(it8); + _cmsFree(it8); } @@ -913,16 +1067,16 @@ static void* AllocBigBlock(LPIT8 it8, size_t size) { LPOWNEDMEM ptr1; - void* ptr = malloc(size); + void* ptr = _cmsMalloc(size); if (ptr) { ZeroMemory(ptr, size); - ptr1 = (LPOWNEDMEM) malloc(sizeof(OWNEDMEM)); + ptr1 = (LPOWNEDMEM) _cmsMalloc(sizeof(OWNEDMEM)); if (ptr1 == NULL) { - free(ptr); + _cmsFree(ptr); return NULL; } @@ -986,8 +1140,9 @@ char *AllocString(LPIT8 it8, const char* str) // Searches through linked list static -BOOL IsAvailableOnList(LPKEYVALUE p, const char* Key, LPKEYVALUE* LastPtr) +LCMSBOOL IsAvailableOnList(LPKEYVALUE p, const char* Key, const char* Subkey, LPKEYVALUE* LastPtr) { + if (LastPtr) *LastPtr = p; for (; p != NULL; p = p->Next) { @@ -996,8 +1151,22 @@ BOOL IsAvailableOnList(LPKEYVALUE p, const char* Key, LPKEYVALUE* LastPtr) if (*Key != '#') { // Comments are ignored if (stricmp(Key, p->Keyword) == 0) - return TRUE; + break; } + } + + if (p == NULL) + return FALSE; + + if (Subkey == 0) + return TRUE; + + for (; p != NULL; p = p->NextSubkey) { + + if (LastPtr) *LastPtr = p; + + if (stricmp(Subkey, p->Subkey) == 0) + return TRUE; } return FALSE; @@ -1007,35 +1176,55 @@ BOOL IsAvailableOnList(LPKEYVALUE p, const char* Key, LPKEYVALUE* LastPtr) // Add a property into a linked list static -BOOL AddToList(LPIT8 it8, LPKEYVALUE* Head, const char *Key, const char* xValue, WRITEMODE WriteAs) +LPKEYVALUE AddToList(LPIT8 it8, LPKEYVALUE* Head, const char *Key, const char *Subkey, const char* xValue, WRITEMODE WriteAs) { LPKEYVALUE p; - LPKEYVALUE last; - // Check if property is already in list (this is an error) - if (IsAvailableOnList(*Head, Key, &last)) { + if (IsAvailableOnList(*Head, Key, Subkey, &p)) { - // This may work for editing properties + // This may work for editing properties - last->Value = AllocString(it8, xValue); - last->WriteAs = WriteAs; - return TRUE; - - // return SynError(it8, "duplicate key <%s>", Key); + // return SynError(it8, "duplicate key <%s>", Key); } + else { + LPKEYVALUE last = p; - // Allocate the container + // Allocate the container p = (LPKEYVALUE) AllocChunk(it8, sizeof(KEYVALUE)); if (p == NULL) { - return SynError(it8, "AddToList: out of memory"); + SynError(it8, "AddToList: out of memory"); + return NULL; } // Store name and value p->Keyword = AllocString(it8, Key); + p->Subkey = (Subkey == NULL) ? NULL : AllocString(it8, Subkey); + // Keep the container in our list + if (*Head == NULL) + *Head = p; + else + { + if(Subkey != 0 && last != 0) { + last->NextSubkey = p; + + // If Subkey is not null, then last is the last property with the same key, + // but not necessarily is the last property in the list, so we need to move + // to the actual list end + while(last->Next != 0) + last = last->Next; + } + last->Next = p; + } + + p->Next = NULL; + p->NextSubkey = NULL; + } + + p->WriteAs = WriteAs; if (xValue != NULL) { p->Value = AllocString(it8, xValue); @@ -1044,29 +1233,20 @@ BOOL AddToList(LPIT8 it8, LPKEYVALUE* Head, const char *Key, const char* xValue, p->Value = NULL; } - p->Next = NULL; - p->WriteAs = WriteAs; - - // Keep the container in our list - if (*Head == NULL) - *Head = p; - else - last->Next = p; - - return TRUE; + return p; } static -BOOL AddAvailableProperty(LPIT8 it8, const char* Key) +LPKEYVALUE AddAvailableProperty(LPIT8 it8, const char* Key, WRITEMODE as) { - return AddToList(it8, &it8->ValidKeywords, Key, NULL, WRITE_UNCOOKED); + return AddToList(it8, &it8->ValidKeywords, Key, NULL, NULL, as); } static -BOOL AddAvailableSampleID(LPIT8 it8, const char* Key) +LPKEYVALUE AddAvailableSampleID(LPIT8 it8, const char* Key) { - return AddToList(it8, &it8->ValidSampleID, Key, NULL, WRITE_UNCOOKED); + return AddToList(it8, &it8->ValidSampleID, Key, NULL, NULL, WRITE_UNCOOKED); } @@ -1122,8 +1302,6 @@ LCMSHANDLE LCMSEXPORT cmsIT8Alloc(void) AllocTable(it8); it8->MemoryBlock = NULL; - it8->Stream[0] = NULL; - it8->IncludeSP = 0; it8->MemorySink = NULL; it8 ->nTable = 0; @@ -1141,6 +1319,8 @@ LCMSHANDLE LCMSEXPORT cmsIT8Alloc(void) it8 -> inum = 0; it8 -> dnum = 0.0; + it8->FileStack[0] = (LPFILECTX)AllocChunk(it8, sizeof(FILECTX)); + it8->IncludeSP = 0; it8 -> lineno = 1; strcpy(it8->DoubleFormatter, DEFAULT_DBL_FORMAT); @@ -1149,7 +1329,7 @@ LCMSHANDLE LCMSEXPORT cmsIT8Alloc(void) // Initialize predefined properties & data for (i=0; i < NUMPREDEFINEDPROPS; i++) - AddAvailableProperty(it8, PredefinedProperties[i]); + AddAvailableProperty(it8, PredefinedProperties[i].id, PredefinedProperties[i].as); for (i=0; i < NUMPREDEFINEDSAMPLEID; i++) AddAvailableSampleID(it8, PredefinedSampleID[i]); @@ -1167,65 +1347,72 @@ const char* LCMSEXPORT cmsIT8GetSheetType(LCMSHANDLE hIT8) } -BOOL LCMSEXPORT cmsIT8SetSheetType(LCMSHANDLE hIT8, const char* Type) +LCMSBOOL LCMSEXPORT cmsIT8SetSheetType(LCMSHANDLE hIT8, const char* Type) { LPIT8 it8 = (LPIT8) hIT8; strncpy(it8 ->SheetType, Type, MAXSTR-1); + it8 ->SheetType[MAXSTR-1] = 0; return TRUE; } -BOOL LCMSEXPORT cmsIT8SetComment(LCMSHANDLE hIT8, const char* Val) +LCMSBOOL LCMSEXPORT cmsIT8SetComment(LCMSHANDLE hIT8, const char* Val) { LPIT8 it8 = (LPIT8) hIT8; if (!Val) return FALSE; if (!*Val) return FALSE; - return AddToList(it8, &GetTable(it8)->HeaderList, "# ", Val, WRITE_UNCOOKED); + return AddToList(it8, &GetTable(it8)->HeaderList, "# ", NULL, Val, WRITE_UNCOOKED) != NULL; } // Sets a property -BOOL LCMSEXPORT cmsIT8SetPropertyStr(LCMSHANDLE hIT8, const char* Key, const char *Val) +LCMSBOOL LCMSEXPORT cmsIT8SetPropertyStr(LCMSHANDLE hIT8, const char* Key, const char *Val) { LPIT8 it8 = (LPIT8) hIT8; if (!Val) return FALSE; if (!*Val) return FALSE; - return AddToList(it8, &GetTable(it8)->HeaderList, Key, Val, WRITE_STRINGIFY); + return AddToList(it8, &GetTable(it8)->HeaderList, Key, NULL, Val, WRITE_STRINGIFY) != NULL; } -BOOL LCMSEXPORT cmsIT8SetPropertyDbl(LCMSHANDLE hIT8, const char* cProp, double Val) +LCMSBOOL LCMSEXPORT cmsIT8SetPropertyDbl(LCMSHANDLE hIT8, const char* cProp, double Val) { LPIT8 it8 = (LPIT8) hIT8; char Buffer[1024]; sprintf(Buffer, it8->DoubleFormatter, Val); - return AddToList(it8, &GetTable(it8)->HeaderList, cProp, Buffer, WRITE_UNCOOKED); + return AddToList(it8, &GetTable(it8)->HeaderList, cProp, NULL, Buffer, WRITE_UNCOOKED) != NULL; } -BOOL LCMSEXPORT cmsIT8SetPropertyHex(LCMSHANDLE hIT8, const char* cProp, int Val) +LCMSBOOL LCMSEXPORT cmsIT8SetPropertyHex(LCMSHANDLE hIT8, const char* cProp, int Val) { LPIT8 it8 = (LPIT8) hIT8; char Buffer[1024]; sprintf(Buffer, "%d", Val); - return AddToList(it8, &GetTable(it8)->HeaderList, cProp, Buffer, WRITE_HEXADECIMAL); + return AddToList(it8, &GetTable(it8)->HeaderList, cProp, NULL, Buffer, WRITE_HEXADECIMAL) != NULL; } -BOOL LCMSEXPORT cmsIT8SetPropertyUncooked(LCMSHANDLE hIT8, const char* Key, const char* Buffer) +LCMSBOOL LCMSEXPORT cmsIT8SetPropertyUncooked(LCMSHANDLE hIT8, const char* Key, const char* Buffer) { LPIT8 it8 = (LPIT8) hIT8; - return AddToList(it8, &GetTable(it8)->HeaderList, Key, Buffer, WRITE_UNCOOKED); + return AddToList(it8, &GetTable(it8)->HeaderList, Key, NULL, Buffer, WRITE_UNCOOKED) != NULL; } +LCMSBOOL LCMSEXPORT cmsIT8SetPropertyMulti(LCMSHANDLE hIT8, const char* Key, const char* SubKey, const char *Buffer) +{ + LPIT8 it8 = (LPIT8) hIT8; + + return AddToList(it8, &GetTable(it8)->HeaderList, Key, SubKey, Buffer, WRITE_PAIR) != NULL; +} // Gets a property const char* LCMSEXPORT cmsIT8GetProperty(LCMSHANDLE hIT8, const char* Key) @@ -1233,7 +1420,7 @@ const char* LCMSEXPORT cmsIT8GetProperty(LCMSHANDLE hIT8, const char* Key) LPIT8 it8 = (LPIT8) hIT8; LPKEYVALUE p; - if (IsAvailableOnList(GetTable(it8) -> HeaderList, Key, &p)) + if (IsAvailableOnList(GetTable(it8) -> HeaderList, Key, NULL, &p)) { return p -> Value; } @@ -1249,6 +1436,18 @@ double LCMSEXPORT cmsIT8GetPropertyDbl(LCMSHANDLE hIT8, const char* cProp) else return 0.0; } +const char* LCMSEXPORT cmsIT8GetPropertyMulti(LCMSHANDLE hIT8, const char* Key, const char *SubKey) +{ + LPIT8 it8 = (LPIT8) hIT8; + LPKEYVALUE p; + + if (IsAvailableOnList(GetTable(it8) -> HeaderList, Key, SubKey, &p)) + { + return p -> Value; + } + return NULL; +} + // ----------------------------------------------------------------- Datasets @@ -1287,10 +1486,17 @@ const char *GetDataFormat(LPIT8 it8, int n) } static -BOOL SetDataFormat(LPIT8 it8, int n, const char *label) +LCMSBOOL SetDataFormat(LPIT8 it8, int n, const char *label) { LPTABLE t = GetTable(it8); +#ifdef STRICT_CGATS + if (!IsAvailableOnList(it8-> ValidSampleID, label, NULL, NULL)) { + SynError(it8, "Invalid data format '%s'.", label); + return FALSE; + } +#endif + if (!t->DataFormat) AllocateDataFormat(it8); @@ -1308,7 +1514,7 @@ BOOL SetDataFormat(LPIT8 it8, int n, const char *label) } -BOOL LCMSEXPORT cmsIT8SetDataFormat(LCMSHANDLE h, int n, const char *Sample) +LCMSBOOL LCMSEXPORT cmsIT8SetDataFormat(LCMSHANDLE h, int n, const char *Sample) { LPIT8 it8 = (LPIT8) h; return SetDataFormat(it8, n, Sample); @@ -1348,7 +1554,7 @@ char* GetData(LPIT8 it8, int nSet, int nField) } static -BOOL SetData(LPIT8 it8, int nSet, int nField, const char *Val) +LCMSBOOL SetData(LPIT8 it8, int nSet, int nField, const char *Val) { LPTABLE t = GetTable(it8); @@ -1383,42 +1589,43 @@ static void WriteStr(LPSAVESTREAM f, const char *str) { - size_t len; + size_t len; - if (str == NULL) - str = " "; + if (str == NULL) + str = " "; - // Lenghth to write - len = strlen(str); + // Lenghth to write + len = strlen(str); f ->Used += len; - if (f ->stream) { // Should I write it to a file? + if (f ->stream) { // Should I write it to a file? - fwrite(str, 1, len, f->stream); + fwrite(str, 1, len, f->stream); + + } + else { // Or to a memory block? + + + if (f ->Base) { // Am I just counting the bytes? + + if (f ->Used > f ->Max) { + + cmsSignalError(LCMS_ERRC_ABORTED, "Write to memory overflows in CGATS parser"); + return; + } + + CopyMemory(f ->Ptr, str, len); + f->Ptr += len; } - else { // Or to a memory block? - - if (f ->Base) { // Am I just counting the bytes? - - if (f ->Used > f ->Max) { - - cmsSignalError(LCMS_ERRC_ABORTED, "Write to memory overflows in CGATS parser"); - return; - } - - CopyMemory(f ->Ptr, str, len); - f->Ptr += len; - - } - - } + } } -// +// Write formatted + static void Writef(LPSAVESTREAM f, const char* frm, ...) { @@ -1426,7 +1633,8 @@ void Writef(LPSAVESTREAM f, const char* frm, ...) va_list args; va_start(args, frm); - vsprintf(Buffer, frm, args); + vsnprintf(Buffer, 4095, frm, args); + Buffer[4095] = 0; WriteStr(f, Buffer); va_end(args); @@ -1450,7 +1658,7 @@ void WriteHeader(LPIT8 it8, LPSAVESTREAM fp) for (Pt = p ->Value; *Pt; Pt++) { - Writef(fp, "%c", *Pt); + Writef(fp, "%c", *Pt); if (*Pt == '\n') { WriteStr(fp, "# "); @@ -1462,7 +1670,7 @@ void WriteHeader(LPIT8 it8, LPSAVESTREAM fp) } - if (!IsAvailableOnList(it8-> ValidKeywords, p->Keyword, NULL)) { + if (!IsAvailableOnList(it8-> ValidKeywords, p->Keyword, NULL, NULL)) { #ifdef STRICT_CGATS WriteStr(fp, "KEYWORD\t\""); @@ -1470,7 +1678,7 @@ void WriteHeader(LPIT8 it8, LPSAVESTREAM fp) WriteStr(fp, "\"\n"); #endif - AddAvailableProperty(it8, p->Keyword); + AddAvailableProperty(it8, p->Keyword, WRITE_UNCOOKED); } @@ -1495,6 +1703,10 @@ void WriteHeader(LPIT8 it8, LPSAVESTREAM fp) Writef(fp, "\t0x%B", atoi(p ->Value)); break; + case WRITE_PAIR: + Writef(fp, "\t\"%s,%s\"", p->Subkey, p->Value); + break; + default: SynError(it8, "Unknown write mode %d", p ->WriteAs); return; } @@ -1573,13 +1785,13 @@ void WriteData(LPSAVESTREAM fp, LPIT8 it8) // Saves whole file -BOOL LCMSEXPORT cmsIT8SaveToFile(LCMSHANDLE hIT8, const char* cFileName) +LCMSBOOL LCMSEXPORT cmsIT8SaveToFile(LCMSHANDLE hIT8, const char* cFileName) { SAVESTREAM sd; int i; LPIT8 it8 = (LPIT8) hIT8; - ZeroMemory(&sd, sizeof(SAVESTREAM)); + ZeroMemory(&sd, sizeof(SAVESTREAM)); sd.stream = fopen(cFileName, "wt"); if (!sd.stream) return FALSE; @@ -1594,31 +1806,31 @@ BOOL LCMSEXPORT cmsIT8SaveToFile(LCMSHANDLE hIT8, const char* cFileName) WriteData(&sd, it8); } - fclose(sd.stream); + fclose(sd.stream); return TRUE; } // Saves to memory -BOOL LCMSEXPORT cmsIT8SaveToMem(LCMSHANDLE hIT8, void *MemPtr, size_t* BytesNeeded) +LCMSBOOL LCMSEXPORT cmsIT8SaveToMem(LCMSHANDLE hIT8, void *MemPtr, size_t* BytesNeeded) { SAVESTREAM sd; int i; LPIT8 it8 = (LPIT8) hIT8; - ZeroMemory(&sd, sizeof(SAVESTREAM)); + ZeroMemory(&sd, sizeof(SAVESTREAM)); sd.stream = NULL; - sd.Base = (LPBYTE) MemPtr; - sd.Ptr = sd.Base; + sd.Base = (LPBYTE) MemPtr; + sd.Ptr = sd.Base; - sd.Used = 0; + sd.Used = 0; - if (sd.Base) - sd.Max = *BytesNeeded; // Write to memory? - else - sd.Max = 0; // Just counting the needed bytes + if (sd.Base) + sd.Max = *BytesNeeded; // Write to memory? + else + sd.Max = 0; // Just counting the needed bytes WriteStr(&sd, it8->SheetType); WriteStr(&sd, "\n"); @@ -1630,12 +1842,12 @@ BOOL LCMSEXPORT cmsIT8SaveToMem(LCMSHANDLE hIT8, void *MemPtr, size_t* BytesNeed WriteData(&sd, it8); } - sd.Used++; // The \0 at the very end + sd.Used++; // The \0 at the very end - if (sd.Base) - sd.Ptr = 0; + if (sd.Base) + sd.Ptr = 0; - *BytesNeeded = sd.Used; + *BytesNeeded = sd.Used; return TRUE; } @@ -1644,7 +1856,7 @@ BOOL LCMSEXPORT cmsIT8SaveToMem(LCMSHANDLE hIT8, void *MemPtr, size_t* BytesNeed // -------------------------------------------------------------- Higer level parsing static -BOOL DataFormatSection(LPIT8 it8) +LCMSBOOL DataFormatSection(LPIT8 it8) { int iField = 0; LPTABLE t = GetTable(it8); @@ -1685,16 +1897,19 @@ BOOL DataFormatSection(LPIT8 it8) static -BOOL DataSection (LPIT8 it8) +LCMSBOOL DataSection (LPIT8 it8) { int iField = 0; int iSet = 0; - char Buffer[256]; + char Buffer[MAXSTR]; LPTABLE t = GetTable(it8); InSymbol(it8); // Eats "BEGIN_DATA" CheckEOLN(it8); + if (!t->Data) + AllocateDataSet(it8); + while (it8->sy != SEND_DATA && it8->sy != SEOF) { if (iField >= t -> nSamples) { @@ -1705,7 +1920,7 @@ BOOL DataSection (LPIT8 it8) if (it8->sy != SEND_DATA && it8->sy != SEOF) { - if (!GetVal(it8, Buffer, "Sample data expected")) + if (!GetVal(it8, Buffer, 255, "Sample data expected")) return FALSE; if (!SetData(it8, iSet, iField, Buffer)) @@ -1734,10 +1949,11 @@ BOOL DataSection (LPIT8 it8) static -BOOL HeaderSection(LPIT8 it8) +LCMSBOOL HeaderSection(LPIT8 it8) { char VarName[MAXID]; char Buffer[MAXSTR]; + LPKEYVALUE Key; while (it8->sy != SEOF && it8->sy != SSYNERROR && @@ -1749,30 +1965,79 @@ BOOL HeaderSection(LPIT8 it8) case SKEYWORD: InSymbol(it8); - if (!GetVal(it8, Buffer, "Keyword expected")) return FALSE; - if (!AddAvailableProperty(it8, Buffer)) return FALSE; + if (!GetVal(it8, Buffer, MAXSTR-1, "Keyword expected")) return FALSE; + if (!AddAvailableProperty(it8, Buffer, WRITE_UNCOOKED)) return FALSE; + InSymbol(it8); + break; + + + case SDATA_FORMAT_ID: + InSymbol(it8); + if (!GetVal(it8, Buffer, MAXSTR-1, "Keyword expected")) return FALSE; + if (!AddAvailableSampleID(it8, Buffer)) return FALSE; InSymbol(it8); break; case SIDENT: strncpy(VarName, it8->id, MAXID-1); + VarName[MAXID-1] = 0; - if (!IsAvailableOnList(it8-> ValidKeywords, VarName, NULL)) { + if (!IsAvailableOnList(it8-> ValidKeywords, VarName, NULL, &Key)) { #ifdef STRICT_CGATS return SynError(it8, "Undefined keyword '%s'", VarName); #else - if (!AddAvailableProperty(it8, VarName)) return FALSE; + Key = AddAvailableProperty(it8, VarName, WRITE_UNCOOKED); + if (Key == NULL) return FALSE; #endif } InSymbol(it8); - if (!GetVal(it8, Buffer, "Property data expected")) return FALSE; + if (!GetVal(it8, Buffer, MAXSTR-1, "Property data expected")) return FALSE; + if(Key->WriteAs != WRITE_PAIR) { + AddToList(it8, &GetTable(it8)->HeaderList, VarName, NULL, Buffer, + (it8->sy == SSTRING) ? WRITE_STRINGIFY : WRITE_UNCOOKED); + } + else { + const char *Subkey; + char *Nextkey; + if (it8->sy != SSTRING) + return SynError(it8, "Invalid value '%s' for property '%s'.", Buffer, VarName); - AddToList(it8, &GetTable(it8)->HeaderList, VarName, Buffer, - (it8->sy == SSTRING) ? WRITE_STRINGIFY : WRITE_UNCOOKED); + // chop the string as a list of "subkey, value" pairs, using ';' as a separator + for(Subkey = Buffer; Subkey != NULL; Subkey = Nextkey) + { + char *Value, *temp; + + // identify token pair boundary + Nextkey = (char*) strchr(Subkey, ';'); + if(Nextkey) + *Nextkey++ = '\0'; + + // for each pair, split the subkey and the value + Value = (char*) strrchr(Subkey, ','); + if(Value == NULL) + return SynError(it8, "Invalid value for property '%s'.", VarName); + + // gobble the spaces before the coma, and the coma itself + temp = Value++; + do *temp-- = '\0'; while(temp >= Subkey && *temp == ' '); + + // gobble any space at the right + temp = Value + strlen(Value) - 1; + while(*temp == ' ') *temp-- = '\0'; + + // trim the strings from the left + Subkey += strspn(Subkey, " "); + Value += strspn(Value, " "); + + if(Subkey[0] == 0 || Value[0] == 0) + return SynError(it8, "Invalid value for property '%s'.", VarName); + AddToList(it8, &GetTable(it8)->HeaderList, VarName, Subkey, Value, WRITE_PAIR); + } + } InSymbol(it8); break; @@ -1793,22 +2058,23 @@ BOOL HeaderSection(LPIT8 it8) static -BOOL ParseIT8(LPIT8 it8) +LCMSBOOL ParseIT8(LPIT8 it8, LCMSBOOL nosheet) { - char* SheetTypePtr; + char* SheetTypePtr = it8 ->SheetType; + + if (nosheet == 0) { // First line is a very special case. while (isseparator(it8->ch)) NextCh(it8); - SheetTypePtr = it8 ->SheetType; - while (it8->ch != '\r' && it8 ->ch != '\n' && it8->ch != '\t' && it8 -> ch != -1) { *SheetTypePtr++= (char) it8 ->ch; NextCh(it8); } + } *SheetTypePtr = 0; InSymbol(it8); @@ -1869,6 +2135,12 @@ void CookPointers(LPIT8 it8) for (idField = 0; idField < t -> nSamples; idField++) { + if (t ->DataFormat == NULL) { + SynError(it8, "Undefined DATA_FORMAT"); + return; + + } + Fld = t->DataFormat[idField]; if (!Fld) continue; @@ -1884,6 +2156,7 @@ void CookPointers(LPIT8 it8) char Buffer[256]; strncpy(Buffer, Data, 255); + Buffer[255] = 0; if (strlen(Buffer) <= strlen(Data)) strcpy(Data, Buffer); @@ -1916,7 +2189,7 @@ void CookPointers(LPIT8 it8) LPTABLE Table = it8 ->Tab + k; LPKEYVALUE p; - if (IsAvailableOnList(Table->HeaderList, Label, &p)) { + if (IsAvailableOnList(Table->HeaderList, Label, NULL, &p)) { // Available, keep type and table char Buffer[256]; @@ -1924,7 +2197,7 @@ void CookPointers(LPIT8 it8) char *Type = p ->Value; int nTable = k; - sprintf(Buffer, "%s %d %s", Label, nTable, Type ); + snprintf(Buffer, 255, "%s %d %s", Label, nTable, Type ); SetData(it8, i, idField, Buffer); } @@ -1948,8 +2221,9 @@ void CookPointers(LPIT8 it8) // that should be something like some printable characters plus a \n static -BOOL IsMyBlock(LPBYTE Buffer, size_t n) +int IsMyBlock(LPBYTE Buffer, size_t n) { + int cols = 1, space = 0, quot = 0; size_t i; if (n < 10) return FALSE; // Too small @@ -1959,9 +2233,26 @@ BOOL IsMyBlock(LPBYTE Buffer, size_t n) for (i = 1; i < n; i++) { - if (Buffer[i] == '\n' || Buffer[i] == '\r' || Buffer[i] == '\t') return TRUE; - if (Buffer[i] < 32) return FALSE; - + switch(Buffer[i]) + { + case '\n': + case '\r': + return quot == 1 || cols > 2 ? 0 : cols; + case '\t': + case ' ': + if(!quot && !space) + space = 1; + break; + case '\"': + quot = !quot; + break; + default: + if (Buffer[i] < 32) return 0; + if (Buffer[i] > 127) return 0; + cols += space; + space = 0; + break; + } } return FALSE; @@ -1970,7 +2261,7 @@ BOOL IsMyBlock(LPBYTE Buffer, size_t n) static -BOOL IsMyFile(const char* FileName) +int IsMyFile(const char* FileName) { FILE *fp; size_t Size; @@ -1998,21 +2289,22 @@ LCMSHANDLE LCMSEXPORT cmsIT8LoadFromMem(void *Ptr, size_t len) LCMSHANDLE hIT8; LPIT8 it8; - if (!IsMyBlock((LPBYTE) Ptr, len)) return NULL; + int type = IsMyBlock((LPBYTE) Ptr, len); + if (type == 0) return NULL; hIT8 = cmsIT8Alloc(); if (!hIT8) return NULL; it8 = (LPIT8) hIT8; - it8 ->MemoryBlock = (char*) malloc(len + 1); + it8 ->MemoryBlock = (char*) _cmsMalloc(len + 1); strncpy(it8 ->MemoryBlock, (const char*) Ptr, len); it8 ->MemoryBlock[len] = 0; - strncpy(it8->FileName, "", MAX_PATH-1); + strncpy(it8->FileStack[0]->FileName, "", MAX_PATH-1); it8-> Source = it8 -> MemoryBlock; - if (!ParseIT8(it8)) { + if (!ParseIT8(it8, type-1)) { cmsIT8Free(hIT8); return FALSE; @@ -2021,7 +2313,7 @@ LCMSHANDLE LCMSEXPORT cmsIT8LoadFromMem(void *Ptr, size_t len) CookPointers(it8); it8 ->nTable = 0; - free(it8->MemoryBlock); + _cmsFree(it8->MemoryBlock); it8 -> MemoryBlock = NULL; return hIT8; @@ -2036,26 +2328,28 @@ LCMSHANDLE LCMSEXPORT cmsIT8LoadFromFile(const char* cFileName) LCMSHANDLE hIT8; LPIT8 it8; - if (!IsMyFile(cFileName)) return NULL; + int type = IsMyFile(cFileName); + if (type == 0) return NULL; hIT8 = cmsIT8Alloc(); it8 = (LPIT8) hIT8; if (!hIT8) return NULL; - it8 ->Stream[0] = fopen(cFileName, "rt"); + it8 ->FileStack[0]->Stream = fopen(cFileName, "rt"); - if (!it8 ->Stream[0]) { + if (!it8 ->FileStack[0]->Stream) { cmsIT8Free(hIT8); return NULL; } - strncpy(it8->FileName, cFileName, MAX_PATH-1); + strncpy(it8->FileStack[0]->FileName, cFileName, MAX_PATH-1); + it8->FileStack[0]->FileName[MAX_PATH-1] = 0; - if (!ParseIT8(it8)) { + if (!ParseIT8(it8, type-1)) { - fclose(it8 ->Stream[0]); + fclose(it8 ->FileStack[0]->Stream); cmsIT8Free(hIT8); return NULL; } @@ -2063,7 +2357,7 @@ LCMSHANDLE LCMSEXPORT cmsIT8LoadFromFile(const char* cFileName) CookPointers(it8); it8 ->nTable = 0; - fclose(it8 ->Stream[0]); + fclose(it8 ->FileStack[0]->Stream); return hIT8; } @@ -2078,12 +2372,12 @@ int LCMSEXPORT cmsIT8EnumDataFormat(LCMSHANDLE hIT8, char ***SampleNames) } -int LCMSEXPORT cmsIT8EnumProperties(LCMSHANDLE hIT8, char ***PropertyNames) +int LCMSEXPORT cmsIT8EnumProperties(LCMSHANDLE hIT8, const char ***PropertyNames) { LPIT8 it8 = (LPIT8) hIT8; LPKEYVALUE p; int n; - char **Props; + const char **Props; LPTABLE t = GetTable(it8); // Pass#1 - count properties @@ -2094,7 +2388,7 @@ int LCMSEXPORT cmsIT8EnumProperties(LCMSHANDLE hIT8, char ***PropertyNames) } - Props = (char **) AllocChunk(it8, sizeof(char *) * n); + Props = (const char **) AllocChunk(it8, sizeof(char *) * n); // Pass#2 - Fill pointers n = 0; @@ -2106,6 +2400,41 @@ int LCMSEXPORT cmsIT8EnumProperties(LCMSHANDLE hIT8, char ***PropertyNames) return n; } +int LCMSEXPORT cmsIT8EnumPropertyMulti(LCMSHANDLE hIT8, const char* cProp, const char ***SubpropertyNames) +{ + LPIT8 it8 = (LPIT8) hIT8; + LPKEYVALUE p, tmp; + int n; + const char **Props; + LPTABLE t = GetTable(it8); + + if(!IsAvailableOnList(t->HeaderList, cProp, NULL, &p)) { + *SubpropertyNames = 0; + return 0; + } + + // Pass#1 - count properties + + n = 0; + for (tmp = p; tmp != NULL; tmp = tmp->NextSubkey) { + if(tmp->Subkey != NULL) + n++; + } + + + Props = (const char **) AllocChunk(it8, sizeof(char *) * n); + + // Pass#2 - Fill pointers + n = 0; + for (tmp = p; tmp != NULL; tmp = tmp->NextSubkey) { + if(tmp->Subkey != NULL) + Props[n++] = p ->Subkey; + } + + *SubpropertyNames = Props; + return n; +} + static int LocatePatch(LPIT8 it8, const char* cPatch) { @@ -2201,7 +2530,7 @@ double LCMSEXPORT cmsIT8GetDataRowColDbl(LCMSHANDLE hIT8, int row, int col) } -BOOL LCMSEXPORT cmsIT8SetDataRowCol(LCMSHANDLE hIT8, int row, int col, const char* Val) +LCMSBOOL LCMSEXPORT cmsIT8SetDataRowCol(LCMSHANDLE hIT8, int row, int col, const char* Val) { LPIT8 it8 = (LPIT8) hIT8; @@ -2209,7 +2538,7 @@ BOOL LCMSEXPORT cmsIT8SetDataRowCol(LCMSHANDLE hIT8, int row, int col, const cha } -BOOL LCMSEXPORT cmsIT8SetDataRowColDbl(LCMSHANDLE hIT8, int row, int col, double Val) +LCMSBOOL LCMSEXPORT cmsIT8SetDataRowColDbl(LCMSHANDLE hIT8, int row, int col, double Val) { LPIT8 it8 = (LPIT8) hIT8; char Buff[256]; @@ -2260,7 +2589,7 @@ double LCMSEXPORT cmsIT8GetDataDbl(LCMSHANDLE it8, const char* cPatch, const cha -BOOL LCMSEXPORT cmsIT8SetData(LCMSHANDLE hIT8, const char* cPatch, +LCMSBOOL LCMSEXPORT cmsIT8SetData(LCMSHANDLE hIT8, const char* cPatch, const char* cSample, const char *Val) { @@ -2305,18 +2634,19 @@ BOOL LCMSEXPORT cmsIT8SetData(LCMSHANDLE hIT8, const char* cPatch, } -BOOL LCMSEXPORT cmsIT8SetDataDbl(LCMSHANDLE hIT8, const char* cPatch, +LCMSBOOL LCMSEXPORT cmsIT8SetDataDbl(LCMSHANDLE hIT8, const char* cPatch, const char* cSample, double Val) { LPIT8 it8 = (LPIT8) hIT8; char Buff[256]; - sprintf(Buff, it8->DoubleFormatter, Val); + snprintf(Buff, 255, it8->DoubleFormatter, Val); return cmsIT8SetData(hIT8, cPatch, cSample, Buff); } +// Buffer should get MAXSTR at least const char* LCMSEXPORT cmsIT8GetPatchName(LCMSHANDLE hIT8, int nPatch, char* buffer) { @@ -2327,10 +2657,16 @@ const char* LCMSEXPORT cmsIT8GetPatchName(LCMSHANDLE hIT8, int nPatch, char* buf if (!Data) return NULL; if (!buffer) return Data; - strcpy(buffer, Data); + strncpy(buffer, Data, MAXSTR-1); + buffer[MAXSTR-1] = 0; return buffer; } +int LCMSEXPORT cmsIT8GetPatchByName(LCMSHANDLE hIT8, const char *cPatch) +{ + return LocatePatch((LPIT8)hIT8, cPatch); +} + int LCMSEXPORT cmsIT8TableCount(LCMSHANDLE hIT8) { LPIT8 it8 = (LPIT8) hIT8; @@ -2356,7 +2692,7 @@ int LCMSEXPORT cmsIT8SetTableByLabel(LCMSHANDLE hIT8, const char* cSet, const ch cLabelFld = cmsIT8GetData(hIT8, cSet, cField); if (!cLabelFld) return -1; - if (sscanf(cLabelFld, "%s %d %s", Label, &nTable, Type) != 3) + if (sscanf(cLabelFld, "%255s %d %255s", Label, &nTable, Type) != 3) return -1; if (ExpectedType != NULL && *ExpectedType == 0) @@ -2371,6 +2707,19 @@ int LCMSEXPORT cmsIT8SetTableByLabel(LCMSHANDLE hIT8, const char* cSet, const ch } +LCMSBOOL LCMSEXPORT cmsIT8SetIndexColumn(LCMSHANDLE hIT8, const char* cSample) +{ + LPIT8 it8 = (LPIT8) hIT8; + + int pos = LocateSample(it8, cSample); + if(pos == -1) + return FALSE; + + it8->Tab[it8->nTable].SampleID = pos; + return TRUE; +} + + void LCMSEXPORT cmsIT8DefineDblFormat(LCMSHANDLE hIT8, const char* Formatter) { LPIT8 it8 = (LPIT8) hIT8; @@ -2380,3 +2729,4 @@ void LCMSEXPORT cmsIT8DefineDblFormat(LCMSHANDLE hIT8, const char* Formatter) else strcpy(it8->DoubleFormatter, Formatter); } + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c index 81579bc4f11..4d56b3ef465 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -256,7 +256,7 @@ void ComputeBlackPointCompensationFactors(LPcmsCIEXYZ BlackPointIn, // Return TRUE if both m and of are empy -- "m" being identity and "of" being 0 static -BOOL IdentityParameters(LPWMAT3 m, LPWVEC3 of) +LCMSBOOL IdentityParameters(LPWMAT3 m, LPWVEC3 of) { WVEC3 wv0; @@ -661,3 +661,6 @@ int cmsChooseCnvrt(int Absolute, return rc; } + + + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c index 016d0c4c669..a8947d4aee9 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -57,6 +57,7 @@ // errors. void cdecl cmsSignalError(int ErrorCode, const char *ErrorText, ...); + int LCMSEXPORT cmsErrorAction(int lAbort); void LCMSEXPORT cmsSetErrorHandler(cmsErrorHandlerFunction Fn); @@ -96,7 +97,7 @@ void cmsSignalError(int ErrorCode, const char *ErrorText, ...) char Buffer[1024]; - vsprintf(Buffer, ErrorText, args); + vsnprintf(Buffer, 1023, ErrorText, args); va_end(args); if (UserErrorHandler(ErrorCode, Buffer)) { @@ -118,8 +119,8 @@ void cmsSignalError(int ErrorCode, const char *ErrorText, ...) char Buffer1[1024]; char Buffer2[256]; - sprintf(Buffer1, "Error #%x; ", ErrorCode); - vsprintf(Buffer2, ErrorText, args); + snprintf(Buffer1, 767, "Error #%x; ", ErrorCode); + vsnprintf(Buffer2, 255, ErrorText, args); strcat(Buffer1, Buffer2); MessageBox(NULL, Buffer1, "Little cms", MB_OK|MB_ICONSTOP|MB_TASKMODAL); diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c index 1b223c61342..7d134389dff 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -63,9 +63,9 @@ LPGAMMATABLE LCMSEXPORT cmsReverseGamma(int nResultSamples, LPGAMMATABLE InGamma LPGAMMATABLE LCMSEXPORT cmsBuildParametricGamma(int nEntries, int Type, double Params[]); LPGAMMATABLE LCMSEXPORT cmsJoinGamma(LPGAMMATABLE InGamma, LPGAMMATABLE OutGamma); LPGAMMATABLE LCMSEXPORT cmsJoinGammaEx(LPGAMMATABLE InGamma, LPGAMMATABLE OutGamma, int nPoints); -BOOL LCMSEXPORT cmsSmoothGamma(LPGAMMATABLE Tab, double lambda); +LCMSBOOL LCMSEXPORT cmsSmoothGamma(LPGAMMATABLE Tab, double lambda); -BOOL cdecl _cmsSmoothEndpoints(LPWORD Table, int nPoints); +LCMSBOOL cdecl _cmsSmoothEndpoints(LPWORD Table, int nPoints); // Sampled curves @@ -74,7 +74,7 @@ LPSAMPLEDCURVE cdecl cmsAllocSampledCurve(int nItems); void cdecl cmsFreeSampledCurve(LPSAMPLEDCURVE p); void cdecl cmsEndpointsOfSampledCurve(LPSAMPLEDCURVE p, double* Min, double* Max); void cdecl cmsClampSampledCurve(LPSAMPLEDCURVE p, double Min, double Max); -BOOL cdecl cmsSmoothSampledCurve(LPSAMPLEDCURVE Tab, double SmoothingLambda); +LCMSBOOL cdecl cmsSmoothSampledCurve(LPSAMPLEDCURVE Tab, double SmoothingLambda); void cdecl cmsRescaleSampledCurve(LPSAMPLEDCURVE p, double Min, double Max, int nPoints); LPSAMPLEDCURVE cdecl cmsJoinSampledCurves(LPSAMPLEDCURVE X, LPSAMPLEDCURVE Y, int nResultingPoints); @@ -84,7 +84,6 @@ double LCMSEXPORT cmsEstimateGammaEx(LPWORD GammaTable, int nEntries, double The // ---------------------------------------------------------------------------------------- -// #define DEBUG 1 #define MAX_KNOTS 4096 typedef float vec[MAX_KNOTS+1]; @@ -144,14 +143,14 @@ LPGAMMATABLE LCMSEXPORT cmsAllocGamma(int nEntries) LPGAMMATABLE p; size_t size; - if (nEntries > 65530) { - cmsSignalError(LCMS_ERRC_WARNING, "Couldn't create gammatable of more than 65530 entries; 65530 assumed"); - nEntries = 65530; + if (nEntries > 65530 || nEntries <= 0) { + cmsSignalError(LCMS_ERRC_ABORTED, "Couldn't create gammatable of more than 65530 entries"); + return NULL; } size = sizeof(GAMMATABLE) + (sizeof(WORD) * (nEntries-1)); - p = (LPGAMMATABLE) malloc(size); + p = (LPGAMMATABLE) _cmsMalloc(size); if (!p) return NULL; ZeroMemory(p, size); @@ -164,7 +163,7 @@ LPGAMMATABLE LCMSEXPORT cmsAllocGamma(int nEntries) void LCMSEXPORT cmsFreeGamma(LPGAMMATABLE Gamma) { - if (Gamma) free(Gamma); + if (Gamma) _cmsFree(Gamma); } @@ -278,6 +277,15 @@ LPGAMMATABLE LCMSEXPORT cmsReverseGamma(int nResultSamples, LPGAMMATABLE InGamma LPWORD InPtr; LPGAMMATABLE p; + // Try to reverse it analytically whatever possible + if (InGamma -> Seed.Type > 0 && InGamma -> Seed.Type <= 5 && + _cmsCrc32OfGammaTable(InGamma) == InGamma -> Seed.Crc32) { + + return cmsBuildParametricGamma(nResultSamples, -(InGamma -> Seed.Type), InGamma ->Seed.Params); + } + + + // Nope, reverse the table p = cmsAllocGamma(nResultSamples); if (!p) return NULL; @@ -528,7 +536,7 @@ void smooth2(vec w, vec y, vec z, float lambda, int m) // Smooths a curve sampled at regular intervals -BOOL LCMSEXPORT cmsSmoothGamma(LPGAMMATABLE Tab, double lambda) +LCMSBOOL LCMSEXPORT cmsSmoothGamma(LPGAMMATABLE Tab, double lambda) { vec w, y, z; @@ -640,13 +648,13 @@ LPSAMPLEDCURVE cmsAllocSampledCurve(int nItems) { LPSAMPLEDCURVE pOut; - pOut = (LPSAMPLEDCURVE) malloc(sizeof(SAMPLEDCURVE)); + pOut = (LPSAMPLEDCURVE) _cmsMalloc(sizeof(SAMPLEDCURVE)); if (pOut == NULL) return NULL; - if((pOut->Values = (double *) malloc(nItems * sizeof(double))) == NULL) + if((pOut->Values = (double *) _cmsMalloc(nItems * sizeof(double))) == NULL) { - free(pOut); + _cmsFree(pOut); return NULL; } @@ -659,8 +667,8 @@ LPSAMPLEDCURVE cmsAllocSampledCurve(int nItems) void cmsFreeSampledCurve(LPSAMPLEDCURVE p) { - free((LPVOID) p -> Values); - free((LPVOID) p); + _cmsFree((LPVOID) p -> Values); + _cmsFree((LPVOID) p); } @@ -731,7 +739,7 @@ void cmsClampSampledCurve(LPSAMPLEDCURVE p, double Min, double Max) // Smooths a curve sampled at regular intervals -BOOL cmsSmoothSampledCurve(LPSAMPLEDCURVE Tab, double lambda) +LCMSBOOL cmsSmoothSampledCurve(LPSAMPLEDCURVE Tab, double lambda) { vec w, y, z; int i, nItems; @@ -915,14 +923,11 @@ LPSAMPLEDCURVE cmsConvertGammaToSampledCurve(LPGAMMATABLE Gamma, int nPoints) // Smooth endpoints (used in Black/White compensation) -BOOL _cmsSmoothEndpoints(LPWORD Table, int nEntries) +LCMSBOOL _cmsSmoothEndpoints(LPWORD Table, int nEntries) { vec w, y, z; int i, Zeros, Poles; -#ifdef DEBUG - ASAVE(Table, nEntries, "nonsmt.txt"); -#endif if (cmsIsLinear(Table, nEntries)) return FALSE; // Nothing to do diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c index 071cb4e4774..90e9181dcdb 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -66,7 +66,7 @@ to use highlights, then it will be lost. */ -BOOL _cmsEndPointsBySpace(icColorSpaceSignature Space, WORD **White, WORD **Black, +LCMSBOOL _cmsEndPointsBySpace(icColorSpaceSignature Space, WORD **White, WORD **Black, int *nOutputs) { // Only most common spaces @@ -376,7 +376,6 @@ double LCMSEXPORT cmsCIE2000DeltaE(LPcmsCIELab Lab1, LPcmsCIELab Lab2, double bs = Lab2 ->b; double Cs = sqrt( Sqr(as) + Sqr(bs) ); - double G = 0.5 * ( 1 - sqrt(pow((C + Cs) / 2 , 7.0) / (pow((C + Cs) / 2, 7.0) + pow(25.0, 7.0) ) )); double a_p = (1 + G ) * a1; @@ -390,15 +389,21 @@ double LCMSEXPORT cmsCIE2000DeltaE(LPcmsCIELab Lab1, LPcmsCIELab Lab2, double C_ps = sqrt(Sqr(a_ps) + Sqr(b_ps)); double h_ps = atan2deg(a_ps, b_ps); - - double meanC_p =(C_p + C_ps) / 2; - double meanh_p = fabs(h_ps-h_p) <= 180 ? (h_ps + h_p)/2 : (h_ps+h_p-360)/2; + double hps_plus_hp = h_ps + h_p; + double hps_minus_hp = h_ps - h_p; + + double meanh_p = fabs(hps_minus_hp) <= 180.000001 ? (hps_plus_hp)/2 : + (hps_plus_hp) < 360 ? (hps_plus_hp + 360)/2 : + (hps_plus_hp - 360)/2; + + double delta_h = (hps_minus_hp) <= -180.000001 ? (hps_minus_hp + 360) : + (hps_minus_hp) > 180 ? (hps_minus_hp - 360) : + (hps_minus_hp); + double delta_L = (Ls - L1); + double delta_C = (C_ps - C_p ); - double delta_h = fabs(h_p - h_ps) <= 180 ? fabs(h_p - h_ps) : 360 - fabs(h_p - h_ps); - double delta_L = fabs(L1 - Ls); - double delta_C = fabs(C_p - C_ps); double delta_H =2 * sqrt(C_ps*C_p) * sin(RADIANES(delta_h) / 2); @@ -1065,7 +1070,7 @@ void SlopeLimiting(WORD Table[], int nEntries) // Check for monotonicity. static -BOOL IsMonotonic(LPGAMMATABLE t) +LCMSBOOL IsMonotonic(LPGAMMATABLE t) { int n = t -> nEntries; int i, last; @@ -1088,7 +1093,7 @@ BOOL IsMonotonic(LPGAMMATABLE t) // Check for endpoints static -BOOL HasProperEndpoints(LPGAMMATABLE t) +LCMSBOOL HasProperEndpoints(LPGAMMATABLE t) { if (t ->GammaTable[0] != 0) return FALSE; if (t ->GammaTable[t ->nEntries-1] != 0xFFFF) return FALSE; @@ -1109,7 +1114,7 @@ void _cmsComputePrelinearizationTablesFromXFORM(cmsHTRANSFORM h[], int nTransfor unsigned int t, i, v; int j; WORD In[MAXCHANNELS], Out[MAXCHANNELS]; - BOOL lIsSuitable; + LCMSBOOL lIsSuitable; _LPcmsTRANSFORM InputXForm = (_LPcmsTRANSFORM) h[0]; _LPcmsTRANSFORM OutputXForm = (_LPcmsTRANSFORM) h[nTransforms-1]; @@ -1126,10 +1131,10 @@ void _cmsComputePrelinearizationTablesFromXFORM(cmsHTRANSFORM h[], int nTransfor } - // Do nothing on all but RGB to RGB transforms + // Do nothing on all but Gray/RGB to Gray/RGB transforms - if ((InputXForm ->EntryColorSpace != icSigRgbData) || - (OutputXForm->ExitColorSpace != icSigRgbData)) return; + if (((InputXForm ->EntryColorSpace != icSigRgbData) && (InputXForm ->EntryColorSpace != icSigGrayData)) || + ((OutputXForm->ExitColorSpace != icSigRgbData) && (OutputXForm->ExitColorSpace != icSigGrayData))) return; for (t = 0; t < Grid -> InputChan; t++) @@ -1169,10 +1174,13 @@ void _cmsComputePrelinearizationTablesFromXFORM(cmsHTRANSFORM h[], int nTransfor if (!HasProperEndpoints(Trans[t])) lIsSuitable = FALSE; + /* // Exclude if transfer function is not smooth enough // to be modelled as a gamma function, or the gamma is reversed + if (cmsEstimateGamma(Trans[t]) < 1.0) lIsSuitable = FALSE; + */ } diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c index 059f23d0104..43432f37e9b 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -282,7 +282,7 @@ void Eval8Inputs(WORD StageABC[], WORD StageLMN[], WORD LutTable[], LPL16PARAMS // Fills optimization parameters void cmsCalcCLUT16ParamsEx(int nSamples, int InputChan, int OutputChan, - BOOL lUseTetrahedral, LPL16PARAMS p) + LCMSBOOL lUseTetrahedral, LPL16PARAMS p) { int clutPoints; @@ -579,7 +579,7 @@ WORD cmsReverseLinearInterpLUT16(WORD Value, WORD LutTable[], LPL16PARAMS p) // Identify if value fall downto 0 or FFFF zone if (Value == 0) return 0; - if (Value == 0xFFFF) return 0xFFFF; + // if (Value == 0xFFFF) return 0xFFFF; // else restrict to valid zone @@ -631,7 +631,7 @@ WORD cmsReverseLinearInterpLUT16(WORD Value, WORD LutTable[], LPL16PARAMS p) a = (y1 - y0) / (x1 - x0); b = y0 - a * x0; - if (a == 0) return (WORD) x; + if (fabs(a) < 0.01) return (WORD) x; f = ((Value - b) / a); @@ -763,7 +763,7 @@ void cmsTrilinearInterp16(WORD Input[], WORD Output[], X0 = p -> opta3 * x0; X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta3); - Y0 = p -> opta2 * y0; + Y0 = p -> opta2 * y0; Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta2); Z0 = p -> opta1 * z0; @@ -942,7 +942,7 @@ void cmsTetrahedralInterp16(WORD Input[], X0 = p -> opta3 * x0; X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta3); - Y0 = p -> opta2 * y0; + Y0 = p -> opta2 * y0; Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta2); Z0 = p -> opta1 * z0; @@ -1009,11 +1009,11 @@ void cmsTetrahedralInterp16(WORD Input[], Rest = c1 * rx + c2 * ry + c3 * rz; - // There is a lot of math hidden in this expression. The rest is in fixed domain - // and the result in 0..ffff domain. So the complete expression should be - // ROUND_FIXED_TO_INT(ToFixedDomain(Rest)) But that can be optimized as (Rest + 0x7FFF) / 0xFFFF + // There is a lot of math hidden in this expression. The rest is in fixed domain + // and the result in 0..ffff domain. So the complete expression should be + // ROUND_FIXED_TO_INT(ToFixedDomain(Rest)) But that can be optimized as (Rest + 0x7FFF) / 0xFFFF - Output[OutChan] = (WORD) (c0 + ((Rest + 0x7FFF) / 0xFFFF)); + Output[OutChan] = (WORD) (c0 + ((Rest + 0x7FFF) / 0xFFFF)); } @@ -1131,3 +1131,4 @@ void cmsTetrahedralInterp8(WORD Input[], } #undef DENS + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c index d09100d653a..602a3eb943b 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -62,7 +62,7 @@ typedef struct { LPBYTE Block; // Points to allocated memory size_t Size; // Size of allocated memory - int Pointer; // Points to current location + size_t Pointer; // Points to current location int FreeBlockOnClose; // As title } FILEMEM; @@ -70,18 +70,19 @@ typedef struct { static LPVOID MemoryOpen(LPBYTE Block, size_t Size, char Mode) { - FILEMEM* fm = (FILEMEM*) malloc(sizeof(FILEMEM)); + FILEMEM* fm = (FILEMEM*) _cmsMalloc(sizeof(FILEMEM)); + if (fm == NULL) return NULL; + ZeroMemory(fm, sizeof(FILEMEM)); if (Mode == 'r') { - fm ->Block = (LPBYTE) malloc(Size); + fm ->Block = (LPBYTE) _cmsMalloc(Size); if (fm ->Block == NULL) { - free(fm); + _cmsFree(fm); return NULL; } - CopyMemory(fm->Block, Block, Size); fm ->FreeBlockOnClose = TRUE; } @@ -103,13 +104,27 @@ size_t MemoryRead(LPVOID buffer, size_t size, size_t count, struct _lcms_iccprof FILEMEM* ResData = (FILEMEM*) Icc ->stream; LPBYTE Ptr; size_t len = size * count; + size_t extent = ResData -> Pointer + len; + if (len == 0) { + return 0; + } - if (ResData -> Pointer + len > ResData -> Size){ + if (len / size != count) { + cmsSignalError(LCMS_ERRC_ABORTED, "Read from memory error. Integer overflow with count / size."); + return 0; + } + + if (extent < len || extent < ResData -> Pointer) { + cmsSignalError(LCMS_ERRC_ABORTED, "Read from memory error. Integer overflow with len."); + return 0; + } + + if (ResData -> Pointer + len > ResData -> Size) { len = (ResData -> Size - ResData -> Pointer); - cmsSignalError(LCMS_ERRC_WARNING, "Read from memory error. Got %d bytes, block should be of %d bytes", len * size, count * size); - + cmsSignalError(LCMS_ERRC_ABORTED, "Read from memory error. Got %d bytes, block should be of %d bytes", len * size, count * size); + return 0; } Ptr = ResData -> Block; @@ -123,7 +138,7 @@ size_t MemoryRead(LPVOID buffer, size_t size, size_t count, struct _lcms_iccprof // SEEK_CUR is assumed static -BOOL MemorySeek(struct _lcms_iccprofile_struct* Icc, size_t offset) +LCMSBOOL MemorySeek(struct _lcms_iccprofile_struct* Icc, size_t offset) { FILEMEM* ResData = (FILEMEM*) Icc ->stream; @@ -147,10 +162,10 @@ size_t MemoryTell(struct _lcms_iccprofile_struct* Icc) } -// Writes data to memory, also keeps used space for further reference +// Writes data to memory, also keeps used space for further reference. NO CHECK IS PERFORMED static -BOOL MemoryWrite(struct _lcms_iccprofile_struct* Icc, size_t size, void *Ptr) +LCMSBOOL MemoryWrite(struct _lcms_iccprofile_struct* Icc, size_t size, void *Ptr) { FILEMEM* ResData = (FILEMEM*) Icc ->stream; @@ -167,11 +182,17 @@ BOOL MemoryWrite(struct _lcms_iccprofile_struct* Icc, size_t size, void *Ptr) static -BOOL MemoryGrow(struct _lcms_iccprofile_struct* Icc, size_t size) +LCMSBOOL MemoryGrow(struct _lcms_iccprofile_struct* Icc, size_t size) { FILEMEM* ResData = (FILEMEM*) Icc->stream; - void* newBlock = realloc(ResData->Block, ResData->Size + size); + void* newBlock = NULL; + + /* Follow same policies as functions in lcms.h */ + if (ResData->Size + size < 0) return NULL; + if (ResData->Size + size > (size_t)1024*1024*500))) return NULL; + + newBlock = realloc(ResData->Block, ResData->Size + size); if (!newBlock) { return FALSE; @@ -183,15 +204,15 @@ BOOL MemoryGrow(struct _lcms_iccprofile_struct* Icc, size_t size) static -BOOL MemoryClose(struct _lcms_iccprofile_struct* Icc) +LCMSBOOL MemoryClose(struct _lcms_iccprofile_struct* Icc) { FILEMEM* ResData = (FILEMEM*) Icc ->stream; if (ResData ->FreeBlockOnClose) { - if (ResData ->Block) free(ResData ->Block); + if (ResData ->Block) _cmsFree(ResData ->Block); } - free(ResData); + _cmsFree(ResData); return 0; } @@ -209,7 +230,7 @@ size_t FileRead(void *buffer, size_t size, size_t count, struct _lcms_iccprofile { size_t nReaded = fread(buffer, size, count, (FILE*) Icc->stream); if (nReaded != count) { - cmsSignalError(LCMS_ERRC_WARNING, "Read error. Got %d bytes, block should be of %d bytes", nReaded * size, count * size); + cmsSignalError(LCMS_ERRC_ABORTED, "Read error. Got %d bytes, block should be of %d bytes", nReaded * size, count * size); return 0; } @@ -218,7 +239,7 @@ size_t FileRead(void *buffer, size_t size, size_t count, struct _lcms_iccprofile static -BOOL FileSeek(struct _lcms_iccprofile_struct* Icc, size_t offset) +LCMSBOOL FileSeek(struct _lcms_iccprofile_struct* Icc, size_t offset) { if (fseek((FILE*) Icc ->stream, (long) offset, SEEK_SET) != 0) { @@ -240,7 +261,7 @@ size_t FileTell(struct _lcms_iccprofile_struct* Icc) static -BOOL FileWrite(struct _lcms_iccprofile_struct* Icc, size_t size, LPVOID Ptr) +LCMSBOOL FileWrite(struct _lcms_iccprofile_struct* Icc, size_t size, LPVOID Ptr) { if (size == 0) return TRUE; @@ -256,14 +277,14 @@ BOOL FileWrite(struct _lcms_iccprofile_struct* Icc, size_t size, LPVOID Ptr) static -BOOL FileGrow(struct _lcms_iccprofile_struct* Icc, size_t size) +LCMSBOOL FileGrow(struct _lcms_iccprofile_struct* Icc, size_t size) { return TRUE; } static -BOOL FileClose(struct _lcms_iccprofile_struct* Icc) +LCMSBOOL FileClose(struct _lcms_iccprofile_struct* Icc) { return fclose((FILE*) Icc ->stream); } @@ -276,7 +297,7 @@ BOOL FileClose(struct _lcms_iccprofile_struct* Icc) cmsHPROFILE _cmsCreateProfilePlaceholder(void) { - LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) malloc(sizeof(LCMSICCPROFILE)); + LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) _cmsMalloc(sizeof(LCMSICCPROFILE)); if (Icc == NULL) return NULL; // Empty values @@ -314,7 +335,7 @@ icTagSignature LCMSEXPORT cmsGetTagSignature(cmsHPROFILE hProfile, icInt32Number // Search for a specific tag in tag dictionary // Returns position or -1 if tag not found -icInt32Number _cmsSearchTag(LPLCMSICCPROFILE Profile, icTagSignature sig, BOOL lSignalError) +icInt32Number _cmsSearchTag(LPLCMSICCPROFILE Profile, icTagSignature sig, LCMSBOOL lSignalError) { icInt32Number i; @@ -335,7 +356,7 @@ icInt32Number _cmsSearchTag(LPLCMSICCPROFILE Profile, icTagSignature sig, BOOL l // Check existance -BOOL LCMSEXPORT cmsIsTag(cmsHPROFILE hProfile, icTagSignature sig) +LCMSBOOL LCMSEXPORT cmsIsTag(cmsHPROFILE hProfile, icTagSignature sig) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; return _cmsSearchTag(Icc, sig, FALSE) >= 0; @@ -354,7 +375,7 @@ LPVOID _cmsInitTag(LPLCMSICCPROFILE Icc, icTagSignature sig, size_t size, const if (i >=0) { - if (Icc -> TagPtrs[i]) free(Icc -> TagPtrs[i]); + if (Icc -> TagPtrs[i]) _cmsFree(Icc -> TagPtrs[i]); } else { @@ -365,11 +386,14 @@ LPVOID _cmsInitTag(LPLCMSICCPROFILE Icc, icTagSignature sig, size_t size, const cmsSignalError(LCMS_ERRC_ABORTED, "Too many tags (%d)", MAX_TABLE_TAG); Icc ->TagCount = MAX_TABLE_TAG-1; + return NULL; } } - Ptr = malloc(size); + Ptr = _cmsMalloc(size); + if (Ptr == NULL) return NULL; + CopyMemory(Ptr, Init, size); Icc ->TagNames[i] = sig; @@ -400,6 +424,8 @@ LPLCMSICCPROFILE _cmsCreateProfileFromFilePlaceholder(const char* FileName) if (NewIcc == NULL) return NULL; strncpy(NewIcc -> PhysicalFile, FileName, MAX_PATH-1); + NewIcc -> PhysicalFile[MAX_PATH-1] = 0; + NewIcc ->stream = ICCfile; NewIcc ->Read = FileRead; @@ -502,7 +528,7 @@ void _cmsSetSaveToMemory(LPLCMSICCPROFILE Icc, LPVOID MemPtr, size_t dwSize) -BOOL LCMSEXPORT cmsTakeMediaWhitePoint(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile) +LCMSBOOL LCMSEXPORT cmsTakeMediaWhitePoint(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile; *Dest = Icc -> MediaWhitePoint; @@ -510,14 +536,14 @@ BOOL LCMSEXPORT cmsTakeMediaWhitePoint(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile) } -BOOL LCMSEXPORT cmsTakeMediaBlackPoint(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile) +LCMSBOOL LCMSEXPORT cmsTakeMediaBlackPoint(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile; *Dest = Icc -> MediaBlackPoint; return TRUE; } -BOOL LCMSEXPORT cmsTakeIluminant(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile) +LCMSBOOL LCMSEXPORT cmsTakeIluminant(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile; *Dest = Icc -> Illuminant; @@ -575,7 +601,7 @@ void LCMSEXPORT cmsSetProfileID(cmsHPROFILE hProfile, LPBYTE ProfileID) } -BOOL LCMSEXPORT cmsTakeCreationDateTime(struct tm *Dest, cmsHPROFILE hProfile) +LCMSBOOL LCMSEXPORT cmsTakeCreationDateTime(struct tm *Dest, cmsHPROFILE hProfile) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; CopyMemory(Dest, &Icc ->Created, sizeof(struct tm)); @@ -596,23 +622,18 @@ void LCMSEXPORT cmsSetPCS(cmsHPROFILE hProfile, icColorSpaceSignature pcs) Icc -> PCS = pcs; } - - icColorSpaceSignature LCMSEXPORT cmsGetColorSpace(cmsHPROFILE hProfile) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile; return Icc -> ColorSpace; } - - void LCMSEXPORT cmsSetColorSpace(cmsHPROFILE hProfile, icColorSpaceSignature sig) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile; Icc -> ColorSpace = sig; } - icProfileClassSignature LCMSEXPORT cmsGetDeviceClass(cmsHPROFILE hProfile) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile; @@ -625,7 +646,6 @@ DWORD LCMSEXPORT cmsGetProfileICCversion(cmsHPROFILE hProfile) return (DWORD) Icc -> Version; } - void LCMSEXPORT cmsSetProfileICCversion(cmsHPROFILE hProfile, DWORD Version) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile; @@ -664,7 +684,7 @@ LPVOID DupBlock(LPLCMSICCPROFILE Icc, LPVOID Block, size_t size) // This is tricky, since LUT structs does have pointers -BOOL LCMSEXPORT _cmsAddLUTTag(cmsHPROFILE hProfile, icTagSignature sig, const void* lut) +LCMSBOOL LCMSEXPORT _cmsAddLUTTag(cmsHPROFILE hProfile, icTagSignature sig, const void* lut) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; LPLUT Orig, Stored; @@ -692,7 +712,7 @@ BOOL LCMSEXPORT _cmsAddLUTTag(cmsHPROFILE hProfile, icTagSignature sig, const vo } -BOOL LCMSEXPORT _cmsAddXYZTag(cmsHPROFILE hProfile, icTagSignature sig, const cmsCIEXYZ* XYZ) +LCMSBOOL LCMSEXPORT _cmsAddXYZTag(cmsHPROFILE hProfile, icTagSignature sig, const cmsCIEXYZ* XYZ) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; @@ -701,7 +721,7 @@ BOOL LCMSEXPORT _cmsAddXYZTag(cmsHPROFILE hProfile, icTagSignature sig, const cm } -BOOL LCMSEXPORT _cmsAddTextTag(cmsHPROFILE hProfile, icTagSignature sig, const char* Text) +LCMSBOOL LCMSEXPORT _cmsAddTextTag(cmsHPROFILE hProfile, icTagSignature sig, const char* Text) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; @@ -709,7 +729,7 @@ BOOL LCMSEXPORT _cmsAddTextTag(cmsHPROFILE hProfile, icTagSignature sig, const c return TRUE; } -BOOL LCMSEXPORT _cmsAddGammaTag(cmsHPROFILE hProfile, icTagSignature sig, LPGAMMATABLE TransferFunction) +LCMSBOOL LCMSEXPORT _cmsAddGammaTag(cmsHPROFILE hProfile, icTagSignature sig, LPGAMMATABLE TransferFunction) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; @@ -718,7 +738,7 @@ BOOL LCMSEXPORT _cmsAddGammaTag(cmsHPROFILE hProfile, icTagSignature sig, LPGAMM } -BOOL LCMSEXPORT _cmsAddChromaticityTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsCIExyYTRIPLE Chrm) +LCMSBOOL LCMSEXPORT _cmsAddChromaticityTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsCIExyYTRIPLE Chrm) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; @@ -727,7 +747,7 @@ BOOL LCMSEXPORT _cmsAddChromaticityTag(cmsHPROFILE hProfile, icTagSignature sig, } -BOOL LCMSEXPORT _cmsAddSequenceDescriptionTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsSEQ pseq) +LCMSBOOL LCMSEXPORT _cmsAddSequenceDescriptionTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsSEQ pseq) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; @@ -737,28 +757,40 @@ BOOL LCMSEXPORT _cmsAddSequenceDescriptionTag(cmsHPROFILE hProfile, icTagSignatu } -BOOL LCMSEXPORT _cmsAddNamedColorTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsNAMEDCOLORLIST nc) +LCMSBOOL LCMSEXPORT _cmsAddNamedColorTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsNAMEDCOLORLIST nc) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; _cmsInitTag(Icc, sig, sizeof(cmsNAMEDCOLORLIST) + (nc ->nColors - 1) * sizeof(cmsNAMEDCOLOR), nc); - return FALSE; + return TRUE; } -BOOL LCMSEXPORT _cmsAddDateTimeTag(cmsHPROFILE hProfile, icTagSignature sig, struct tm *DateTime) +LCMSBOOL LCMSEXPORT _cmsAddDateTimeTag(cmsHPROFILE hProfile, icTagSignature sig, struct tm *DateTime) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; _cmsInitTag(Icc, sig, sizeof(struct tm), DateTime); - return FALSE; + return TRUE; } -BOOL LCMSEXPORT _cmsAddColorantTableTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsNAMEDCOLORLIST nc) +LCMSBOOL LCMSEXPORT _cmsAddColorantTableTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsNAMEDCOLORLIST nc) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; _cmsInitTag(Icc, sig, sizeof(cmsNAMEDCOLORLIST) + (nc ->nColors - 1) * sizeof(cmsNAMEDCOLOR), nc); - return FALSE; + return TRUE; } + + +LCMSBOOL LCMSEXPORT _cmsAddChromaticAdaptationTag(cmsHPROFILE hProfile, icTagSignature sig, const cmsCIEXYZ* mat) +{ + LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; + + _cmsInitTag(Icc, sig, 3*sizeof(cmsCIEXYZ), mat); + return TRUE; + +} + + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c index 77419f809f3..16aec6c5362 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -149,6 +149,7 @@ void AdjustEndianessArray16(LPWORD p, size_t num_words) #endif + // Transports to properly encoded values - note that icc profiles does use // big endian notation. @@ -216,7 +217,8 @@ icTagTypeSignature ReadBase(LPLCMSICCPROFILE Icc) { icTagBase Base; - Icc -> Read(&Base, sizeof(icTagBase), 1, Icc); + if (Icc -> Read(&Base, sizeof(icTagBase), 1, Icc) != 1) + return (icTagTypeSignature) 0; AdjustEndianess32((LPBYTE) &Base.sig); return Base.sig; @@ -288,13 +290,15 @@ void EvalCHRM(LPcmsCIEXYZ Dest, LPMAT3 Chrm, LPcmsCIEXYZ Src) // Read profile header and validate it static -LPLCMSICCPROFILE ReadHeader(LPLCMSICCPROFILE Icc, BOOL lIsFromMemory) +LPLCMSICCPROFILE ReadHeader(LPLCMSICCPROFILE Icc, LCMSBOOL lIsFromMemory) { icTag Tag; icHeader Header; icInt32Number TagCount, i; + icUInt32Number extent; - Icc -> Read(&Header, sizeof(icHeader), 1, Icc); + if (Icc -> Read(&Header, sizeof(icHeader), 1, Icc) != 1) + goto ErrorCleanup; // Convert endian @@ -306,14 +310,13 @@ LPLCMSICCPROFILE ReadHeader(LPLCMSICCPROFILE Icc, BOOL lIsFromMemory) AdjustEndianess32((LPBYTE) &Header.pcs); AdjustEndianess32((LPBYTE) &Header.magic); AdjustEndianess32((LPBYTE) &Header.flags); - AdjustEndianess32((LPBYTE) &Header.attributes[0]); + AdjustEndianess32((LPBYTE) &Header.attributes[0]); AdjustEndianess32((LPBYTE) &Header.renderingIntent); // Validate it if (Header.magic != icMagicNumber) goto ErrorCleanup; - if (Icc ->Read(&TagCount, sizeof(icInt32Number), 1, Icc) != 1) goto ErrorCleanup; @@ -324,7 +327,7 @@ LPLCMSICCPROFILE ReadHeader(LPLCMSICCPROFILE Icc, BOOL lIsFromMemory) Icc -> PCS = Header.pcs; Icc -> RenderingIntent = (icRenderingIntent) Header.renderingIntent; Icc -> flags = Header.flags; - Icc -> attributes = Header.attributes[0]; + Icc -> attributes = Header.attributes[0]; Icc -> Illuminant.X = Convert15Fixed16(Header.illuminant.X); Icc -> Illuminant.Y = Convert15Fixed16(Header.illuminant.Y); Icc -> Illuminant.Z = Convert15Fixed16(Header.illuminant.Z); @@ -348,7 +351,7 @@ LPLCMSICCPROFILE ReadHeader(LPLCMSICCPROFILE Icc, BOOL lIsFromMemory) // Read tag directory - if (TagCount > MAX_TABLE_TAG) { + if (TagCount > MAX_TABLE_TAG || TagCount < 0) { cmsSignalError(LCMS_ERRC_ABORTED, "Too many tags (%d)", TagCount); goto ErrorCleanup; @@ -357,12 +360,18 @@ LPLCMSICCPROFILE ReadHeader(LPLCMSICCPROFILE Icc, BOOL lIsFromMemory) Icc -> TagCount = TagCount; for (i=0; i < TagCount; i++) { - Icc ->Read(&Tag, sizeof(icTag), 1, Icc); + if (Icc ->Read(&Tag, sizeof(icTag), 1, Icc) != 1) + goto ErrorCleanup; AdjustEndianess32((LPBYTE) &Tag.offset); AdjustEndianess32((LPBYTE) &Tag.size); AdjustEndianess32((LPBYTE) &Tag.sig); // Signature + // Perform some sanity check. Offset + size should fall inside file. + extent = Tag.offset + Tag.size; + if (extent > Header.size || extent < Tag.offset) + goto ErrorCleanup; + Icc -> TagNames[i] = Tag.sig; Icc -> TagOffsets[i] = Tag.offset; Icc -> TagSizes[i] = Tag.size; @@ -381,13 +390,10 @@ ErrorCleanup: cmsSignalError(LCMS_ERRC_ABORTED, "Corrupted profile: '%s'", Icc->PhysicalFile); - free(Icc); + _cmsFree(Icc); return NULL; } - - - static unsigned int uipow(unsigned int a, unsigned int b) { unsigned int rv = 1; @@ -497,7 +503,7 @@ void FixLUT8bothSides(LPLUT Lut, size_t nTabSize) // The infamous LUT 8 static -void ReadLUT8(LPLCMSICCPROFILE Icc, LPLUT NewLUT, icTagSignature sig) +LCMSBOOL ReadLUT8(LPLCMSICCPROFILE Icc, LPLUT NewLUT, icTagSignature sig) { icLut8 LUT8; LPBYTE Temp; @@ -506,7 +512,7 @@ void ReadLUT8(LPLCMSICCPROFILE Icc, LPLUT NewLUT, icTagSignature sig) unsigned int AllLinear; LPWORD PtrW; - Icc ->Read(&LUT8, sizeof(icLut8) - SIZEOF_UINT8_ALIGNED, 1, Icc); + if (Icc ->Read(&LUT8, sizeof(icLut8) - SIZEOF_UINT8_ALIGNED, 1, Icc) != 1) return FALSE; NewLUT -> wFlags = LUT_HASTL1|LUT_HASTL2|LUT_HAS3DGRID; NewLUT -> cLutPoints = LUT8.clutPoints; @@ -515,6 +521,10 @@ void ReadLUT8(LPLCMSICCPROFILE Icc, LPLUT NewLUT, icTagSignature sig) NewLUT -> InputEntries = 256; NewLUT -> OutputEntries = 256; + // Do some checking + if (!_cmsValidateLUT(NewLUT)) { + return FALSE; + } AdjustEndianess32((LPBYTE) &LUT8.e00); AdjustEndianess32((LPBYTE) &LUT8.e01); @@ -550,13 +560,24 @@ void ReadLUT8(LPLCMSICCPROFILE Icc, LPLUT NewLUT, icTagSignature sig) // Copy input tables - Temp = (LPBYTE) malloc(256); + Temp = (LPBYTE) _cmsMalloc(256); + if (Temp == NULL) return FALSE; + AllLinear = 0; for (i=0; i < NewLUT -> InputChan; i++) { - PtrW = (LPWORD) malloc(sizeof(WORD) * 256); + PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * 256); + if (PtrW == NULL) { + _cmsFree(Temp); + return FALSE; + } + NewLUT -> L1[i] = PtrW; - Icc ->Read(Temp, 1, 256, Icc); + if (Icc ->Read(Temp, 1, 256, Icc) != 256) { + _cmsFree(Temp); + return FALSE; + } + for (j=0; j < 256; j++) PtrW[j] = TO16_TAB(Temp[j]); AllLinear += cmsIsLinear(NewLUT -> L1[i], NewLUT -> InputEntries); @@ -569,7 +590,7 @@ void ReadLUT8(LPLCMSICCPROFILE Icc, LPLUT NewLUT, icTagSignature sig) NewLUT -> wFlags &= ~LUT_HASTL1; } - free(Temp); + _cmsFree(Temp); // Copy 3D CLUT @@ -578,9 +599,20 @@ void ReadLUT8(LPLCMSICCPROFILE Icc, LPLUT NewLUT, icTagSignature sig) if (nTabSize > 0) { - PtrW = (LPWORD) malloc(sizeof(WORD) * nTabSize); - Temp = (LPBYTE) malloc(nTabSize); - Icc ->Read(Temp, 1, nTabSize, Icc); + PtrW = (LPWORD) _cmsCalloc(sizeof(WORD), nTabSize); + if (PtrW == NULL) return FALSE; + + Temp = (LPBYTE) _cmsMalloc(nTabSize); + if (Temp == NULL) { + _cmsFree(PtrW); + return FALSE; + } + + if (Icc ->Read(Temp, 1, nTabSize, Icc) != nTabSize) { + _cmsFree(Temp); + _cmsFree(PtrW); + return FALSE; + } NewLUT -> T = PtrW; NewLUT -> Tsize = (unsigned int) (nTabSize * sizeof(WORD)); @@ -589,25 +621,37 @@ void ReadLUT8(LPLCMSICCPROFILE Icc, LPLUT NewLUT, icTagSignature sig) *PtrW++ = TO16_TAB(Temp[i]); } - free(Temp); + _cmsFree(Temp); } else { NewLUT ->T = NULL; NewLUT ->Tsize = 0; - NewLUT -> wFlags &= ~LUT_HAS3DGRID; + NewLUT ->wFlags &= ~LUT_HAS3DGRID; } - // Copy output tables - Temp = (LPBYTE) malloc(256); + Temp = (LPBYTE) _cmsMalloc(256); + if (Temp == NULL) { + return FALSE; + } + AllLinear = 0; for (i=0; i < NewLUT -> OutputChan; i++) { - PtrW = (LPWORD) malloc(sizeof(WORD) * 256); + PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * 256); + if (PtrW == NULL) { + _cmsFree(Temp); + return FALSE; + } + NewLUT -> L2[i] = PtrW; - Icc ->Read(Temp, 1, 256, Icc); + if (Icc ->Read(Temp, 1, 256, Icc) != 256) { + _cmsFree(Temp); + return FALSE; + } + for (j=0; j < 256; j++) PtrW[j] = TO16_TAB(Temp[j]); AllLinear += cmsIsLinear(NewLUT -> L2[i], 256); @@ -621,7 +665,7 @@ void ReadLUT8(LPLCMSICCPROFILE Icc, LPLUT NewLUT, icTagSignature sig) } - free(Temp); + _cmsFree(Temp); cmsCalcL16Params(NewLUT -> InputEntries, &NewLUT -> In16params); cmsCalcL16Params(NewLUT -> OutputEntries, &NewLUT -> Out16params); @@ -646,6 +690,15 @@ void ReadLUT8(LPLCMSICCPROFILE Icc, LPLUT NewLUT, icTagSignature sig) // some profiles does claim to do that. Poor lcms will try // to detect such condition and fix up "on the fly". + switch (sig) { + + case icSigBToA0Tag: + case icSigBToA1Tag: + case icSigBToA2Tag: + case icSigGamutTag: + case icSigPreview0Tag: + case icSigPreview1Tag: + case icSigPreview2Tag: { LPWORD WhiteLab, ExpectedWhite; WORD WhiteFixed[MAXCHANNELS], WhiteUnfixed[MAXCHANNELS]; @@ -685,9 +738,13 @@ void ReadLUT8(LPLCMSICCPROFILE Icc, LPLUT NewLUT, icTagSignature sig) } } + break; + default:; + } } + return TRUE; } @@ -696,7 +753,7 @@ void ReadLUT8(LPLCMSICCPROFILE Icc, LPLUT NewLUT, icTagSignature sig) // Case LUT 16 static -void ReadLUT16(LPLCMSICCPROFILE Icc, LPLUT NewLUT) +LCMSBOOL ReadLUT16(LPLCMSICCPROFILE Icc, LPLUT NewLUT) { icLut16 LUT16; size_t nTabSize; @@ -705,7 +762,8 @@ void ReadLUT16(LPLCMSICCPROFILE Icc, LPLUT NewLUT) LPWORD PtrW; - Icc ->Read(&LUT16, sizeof(icLut16)- SIZEOF_UINT16_ALIGNED, 1, Icc); + if (Icc ->Read(&LUT16, sizeof(icLut16)- SIZEOF_UINT16_ALIGNED, 1, Icc) != 1) + return FALSE; NewLUT -> wFlags = LUT_HASTL1 | LUT_HASTL2 | LUT_HAS3DGRID; NewLUT -> cLutPoints = LUT16.clutPoints; @@ -718,6 +776,9 @@ void ReadLUT16(LPLCMSICCPROFILE Icc, LPLUT NewLUT) NewLUT -> InputEntries = LUT16.inputEnt; NewLUT -> OutputEntries = LUT16.outputEnt; + if (!_cmsValidateLUT(NewLUT)) { + return FALSE; + } // Matrix handling @@ -754,9 +815,14 @@ void ReadLUT16(LPLCMSICCPROFILE Icc, LPLUT NewLUT) AllLinear = 0; for (i=0; i < NewLUT -> InputChan; i++) { - PtrW = (LPWORD) malloc(sizeof(WORD) * NewLUT -> InputEntries); + PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * NewLUT -> InputEntries); + if (PtrW == NULL) return FALSE; + NewLUT -> L1[i] = PtrW; - Icc ->Read(PtrW, sizeof(WORD), NewLUT -> InputEntries, Icc); + if (Icc ->Read(PtrW, sizeof(WORD), NewLUT -> InputEntries, Icc) != NewLUT -> InputEntries) { + return FALSE; + } + AdjustEndianessArray16(PtrW, NewLUT -> InputEntries); AllLinear += cmsIsLinear(NewLUT -> L1[i], NewLUT -> InputEntries); } @@ -775,12 +841,17 @@ void ReadLUT16(LPLCMSICCPROFILE Icc, LPLUT NewLUT) NewLUT->InputChan)); if (nTabSize > 0) { - PtrW = (LPWORD) malloc(sizeof(WORD) * nTabSize); + PtrW = (LPWORD) _cmsCalloc(sizeof(WORD), nTabSize); + if (PtrW == NULL) + return FALSE; NewLUT -> T = PtrW; NewLUT -> Tsize = (unsigned int) (nTabSize * sizeof(WORD)); - Icc -> Read(PtrW, sizeof(WORD), nTabSize, Icc); + if (Icc -> Read(PtrW, sizeof(WORD), nTabSize, Icc) != nTabSize) { + return FALSE; + } + AdjustEndianessArray16(NewLUT -> T, nTabSize); } else { @@ -794,9 +865,16 @@ void ReadLUT16(LPLCMSICCPROFILE Icc, LPLUT NewLUT) AllLinear = 0; for (i=0; i < NewLUT -> OutputChan; i++) { - PtrW = (LPWORD) malloc(sizeof(WORD) * NewLUT -> OutputEntries); + PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * NewLUT -> OutputEntries); + if (PtrW == NULL) { + return FALSE; + } + NewLUT -> L2[i] = PtrW; - Icc ->Read(PtrW, sizeof(WORD), NewLUT -> OutputEntries, Icc); + if (Icc ->Read(PtrW, sizeof(WORD), NewLUT -> OutputEntries, Icc) != NewLUT -> OutputEntries) { + return FALSE; + } + AdjustEndianessArray16(PtrW, NewLUT -> OutputEntries); AllLinear += cmsIsLinear(NewLUT -> L2[i], NewLUT -> OutputEntries); } @@ -814,6 +892,8 @@ void ReadLUT16(LPLCMSICCPROFILE Icc, LPLUT NewLUT) cmsCalcCLUT16Params(NewLUT -> cLutPoints, NewLUT -> InputChan, NewLUT -> OutputChan, &NewLUT -> CLut16params); + + return TRUE; } @@ -830,17 +910,15 @@ LPGAMMATABLE ReadCurve(LPLCMSICCPROFILE Icc) BaseType = ReadBase(Icc); - switch (BaseType) { - case 0x9478ee00L: // Monaco 2 profiler is BROKEN! + case ((icTagTypeSignature) 0x9478ee00): // Monaco 2 profiler is BROKEN! case icSigCurveType: - Icc ->Read(&Count, sizeof(icUInt32Number), 1, Icc); + if (Icc ->Read(&Count, sizeof(icUInt32Number), 1, Icc) != 1) return NULL; AdjustEndianess32((LPBYTE) &Count); - switch (Count) { case 0: // Linear. @@ -855,7 +933,7 @@ LPGAMMATABLE ReadCurve(LPLCMSICCPROFILE Icc) { WORD SingleGammaFixed; - Icc ->Read(&SingleGammaFixed, sizeof(WORD), 1, Icc); + if (Icc ->Read(&SingleGammaFixed, sizeof(WORD), 1, Icc) != 1) return NULL; AdjustEndianess16((LPBYTE) &SingleGammaFixed); return cmsBuildGamma(4096, Convert8Fixed8(SingleGammaFixed)); } @@ -865,10 +943,9 @@ LPGAMMATABLE ReadCurve(LPLCMSICCPROFILE Icc) NewGamma = cmsAllocGamma(Count); if (!NewGamma) return NULL; - Icc ->Read(NewGamma -> GammaTable, sizeof(WORD), Count, Icc); - + if (Icc ->Read(NewGamma -> GammaTable, sizeof(WORD), Count, Icc) != Count) + return NULL; AdjustEndianessArray16(NewGamma -> GammaTable, Count); - return NewGamma; } } @@ -885,11 +962,11 @@ LPGAMMATABLE ReadCurve(LPLCMSICCPROFILE Icc) icUInt16Number Type; int i; - Icc -> Read(&Type, sizeof(icUInt16Number), 1, Icc); - Icc -> Read(&Reserved, sizeof(icUInt16Number), 1, Icc); + if (Icc -> Read(&Type, sizeof(icUInt16Number), 1, Icc) != 1) return NULL; + if (Icc -> Read(&Reserved, sizeof(icUInt16Number), 1, Icc) != 1) return NULL; AdjustEndianess16((LPBYTE) &Type); - if (Type > 5) { + if (Type > 4) { cmsSignalError(LCMS_ERRC_ABORTED, "Unknown parametric curve type '%d' found.", Type); return NULL; @@ -900,7 +977,7 @@ LPGAMMATABLE ReadCurve(LPLCMSICCPROFILE Icc) for (i=0; i < n; i++) { Num = 0; - Icc -> Read(&Num, sizeof(icS15Fixed16Number), 1, Icc); + if (Icc -> Read(&Num, sizeof(icS15Fixed16Number), 1, Icc) != 1) return NULL; Params[i] = Convert15Fixed16(Num); } @@ -938,7 +1015,7 @@ LPGAMMATABLE ReadCurveReversed(LPLCMSICCPROFILE Icc) case 0x9478ee00L: // Monaco 2 profiler is BROKEN! case icSigCurveType: - Icc -> Read(&Count, sizeof(icUInt32Number), 1, Icc); + if (Icc -> Read(&Count, sizeof(icUInt32Number), 1, Icc) != 1) return NULL; AdjustEndianess32((LPBYTE) &Count); @@ -948,6 +1025,7 @@ LPGAMMATABLE ReadCurveReversed(LPLCMSICCPROFILE Icc) NewGamma = cmsAllocGamma(2); if (!NewGamma) return NULL; + NewGamma -> GammaTable[0] = 0; NewGamma -> GammaTable[1] = 0xFFFF; return NewGamma; @@ -955,7 +1033,7 @@ LPGAMMATABLE ReadCurveReversed(LPLCMSICCPROFILE Icc) case 1: { WORD SingleGammaFixed; - Icc -> Read(&SingleGammaFixed, sizeof(WORD), 1, Icc); + if (Icc -> Read(&SingleGammaFixed, sizeof(WORD), 1, Icc) != 1) return NULL; AdjustEndianess16((LPBYTE) &SingleGammaFixed); return cmsBuildGamma(4096, 1./Convert8Fixed8(SingleGammaFixed)); } @@ -965,7 +1043,8 @@ LPGAMMATABLE ReadCurveReversed(LPLCMSICCPROFILE Icc) NewGamma = cmsAllocGamma(Count); if (!NewGamma) return NULL; - Icc -> Read(NewGamma -> GammaTable, sizeof(WORD), Count, Icc); + if (Icc -> Read(NewGamma -> GammaTable, sizeof(WORD), Count, Icc) != Count) + return NULL; AdjustEndianessArray16(NewGamma -> GammaTable, Count); @@ -992,11 +1071,11 @@ LPGAMMATABLE ReadCurveReversed(LPLCMSICCPROFILE Icc) int i; - Icc -> Read(&Type, sizeof(icUInt16Number), 1, Icc); - Icc -> Read(&Reserved, sizeof(icUInt16Number), 1, Icc); + if (Icc -> Read(&Type, sizeof(icUInt16Number), 1, Icc) != 1) return NULL; + if (Icc -> Read(&Reserved, sizeof(icUInt16Number), 1, Icc) != 1) return NULL; AdjustEndianess16((LPBYTE) &Type); - if (Type > 5) { + if (Type > 4) { cmsSignalError(LCMS_ERRC_ABORTED, "Unknown parametric curve type '%d' found.", Type); return NULL; @@ -1006,7 +1085,7 @@ LPGAMMATABLE ReadCurveReversed(LPLCMSICCPROFILE Icc) n = ParamsByType[Type]; for (i=0; i < n; i++) { - Icc -> Read(&Num, sizeof(icS15Fixed16Number), 1, Icc); + if (Icc -> Read(&Num, sizeof(icS15Fixed16Number), 1, Icc) != 1) return NULL; Params[i] = Convert15Fixed16(Num); } @@ -1028,7 +1107,7 @@ LPGAMMATABLE ReadCurveReversed(LPLCMSICCPROFILE Icc) // V4 stuff. Read matrix for LutAtoB and LutBtoA static -BOOL ReadMatrixOffset(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT, DWORD dwFlags) +LCMSBOOL ReadMatrixOffset(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT, DWORD dwFlags) { icS15Fixed16Number All[12]; @@ -1038,7 +1117,8 @@ BOOL ReadMatrixOffset(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT, DWORD d if (Icc -> Seek(Icc, Offset)) return FALSE; - Icc ->Read(All, sizeof(icS15Fixed16Number), 12, Icc); + if (Icc ->Read(All, sizeof(icS15Fixed16Number), 12, Icc) != 12) + return FALSE; for (i=0; i < 12; i++) AdjustEndianess32((LPBYTE) &All[i]); @@ -1067,17 +1147,26 @@ BOOL ReadMatrixOffset(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT, DWORD d // V4 stuff. Read CLUT part for LutAtoB and LutBtoA static -BOOL ReadCLUT(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT) +LCMSBOOL ReadCLUT(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT) { - + unsigned int j; icCLutStruct CLUT; if (Icc -> Seek(Icc, Offset)) return FALSE; - Icc ->Read(&CLUT, sizeof(icCLutStruct), 1, Icc); + if (Icc ->Read(&CLUT, sizeof(icCLutStruct), 1, Icc) != 1) return FALSE; - cmsAlloc3DGrid(NewLUT, CLUT.gridPoints[0], NewLUT ->InputChan, - NewLUT ->OutputChan); + for (j=1; j < NewLUT ->InputChan; j++) { + if (CLUT.gridPoints[0] != CLUT.gridPoints[j]) { + cmsSignalError(LCMS_ERRC_ABORTED, "CLUT with different granulatity is currently unsupported."); + return FALSE; + } + + + } + + if (cmsAlloc3DGrid(NewLUT, CLUT.gridPoints[0], NewLUT ->InputChan, + NewLUT ->OutputChan) == NULL) return FALSE; // Precission can be 1 or 2 bytes @@ -1087,7 +1176,7 @@ BOOL ReadCLUT(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT) unsigned int i; for (i=0; i < NewLUT->Tsize / sizeof(WORD); i++) { - Icc ->Read(&v, sizeof(BYTE), 1, Icc); + if (Icc ->Read(&v, sizeof(BYTE), 1, Icc) != 1) return FALSE; NewLUT->T[i] = TO16_TAB(v); } @@ -1095,10 +1184,10 @@ BOOL ReadCLUT(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT) else if (CLUT.prec == 2) { - Icc ->Read(NewLUT ->T, sizeof(WORD), - NewLUT->Tsize / sizeof(WORD), Icc); + size_t n = NewLUT->Tsize / sizeof(WORD); - AdjustEndianessArray16(NewLUT ->T, NewLUT->Tsize / sizeof(WORD)); + if (Icc ->Read(NewLUT ->T, sizeof(WORD), n, Icc) != n) return FALSE; + AdjustEndianessArray16(NewLUT ->T, NewLUT->Tsize / sizeof(WORD)); } else { cmsSignalError(LCMS_ERRC_ABORTED, "Unknow precission of '%d'", CLUT.prec); @@ -1109,6 +1198,22 @@ BOOL ReadCLUT(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT) } +static +void ResampleCurves(LPGAMMATABLE Curves[], int nCurves) +{ + int i; + LPSAMPLEDCURVE sc; + + for (i=0; i < nCurves; i++) { + sc = cmsConvertGammaToSampledCurve(Curves[i], 4096); + cmsFreeGamma(Curves[i]); + Curves[i] = cmsConvertSampledCurveToGamma(sc, 0xFFFF); + cmsFreeSampledCurve(sc); + } + +} + + static void SkipAlignment(LPLCMSICCPROFILE Icc) { @@ -1121,7 +1226,7 @@ void SkipAlignment(LPLCMSICCPROFILE Icc) // Read a set of curves from specific offset static -BOOL ReadSetOfCurves(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT, int nLocation) +LCMSBOOL ReadSetOfCurves(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT, int nLocation) { LPGAMMATABLE Curves[MAXCHANNELS]; unsigned int i, nCurves; @@ -1134,20 +1239,41 @@ BOOL ReadSetOfCurves(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT, int nLoc else nCurves = NewLUT ->OutputChan; + ZeroMemory(Curves, sizeof(Curves)); for (i=0; i < nCurves; i++) { Curves[i] = ReadCurve(Icc); + if (Curves[i] == NULL) goto Error; SkipAlignment(Icc); + } + // March-26'08: some V4 profiles may have different sampling + // rates, in this case resample all curves to maximum + + for (i=1; i < nCurves; i++) { + if (Curves[i]->nEntries != Curves[0]->nEntries) { + ResampleCurves(Curves, nCurves); + break; + } } NewLUT = cmsAllocLinearTable(NewLUT, Curves, nLocation); + if (NewLUT == NULL) goto Error; for (i=0; i < nCurves; i++) cmsFreeGamma(Curves[i]); return TRUE; +Error: + + for (i=0; i < nCurves; i++) + if (Curves[i]) + cmsFreeGamma(Curves[i]); + + return FALSE; + + } // V4 stuff. LutAtoB type @@ -1160,22 +1286,28 @@ BOOL ReadSetOfCurves(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT, int nLoc // L2 = B curves static -BOOL ReadLUT_A2B(LPLCMSICCPROFILE Icc, LPLUT NewLUT, size_t BaseOffset, icTagSignature sig) +LCMSBOOL ReadLUT_A2B(LPLCMSICCPROFILE Icc, LPLUT NewLUT, size_t BaseOffset, icTagSignature sig) { icLutAtoB LUT16; - Icc ->Read(&LUT16, sizeof(icLutAtoB), 1, Icc); + if (Icc ->Read(&LUT16, sizeof(icLutAtoB), 1, Icc) != 1) return FALSE; NewLUT -> InputChan = LUT16.inputChan; NewLUT -> OutputChan = LUT16.outputChan; + // Validate the NewLUT here to avoid excessive number of channels + // (leading to stack-based buffer overflow in ReadSetOfCurves). + // Needs revalidation after table size is filled in. + if (!_cmsValidateLUT(NewLUT)) { + return FALSE; + } + AdjustEndianess32((LPBYTE) &LUT16.offsetB); AdjustEndianess32((LPBYTE) &LUT16.offsetMat); AdjustEndianess32((LPBYTE) &LUT16.offsetM); AdjustEndianess32((LPBYTE) &LUT16.offsetC); AdjustEndianess32((LPBYTE) &LUT16.offsetA); - if (LUT16.offsetB != 0) ReadSetOfCurves(Icc, BaseOffset + LUT16.offsetB, NewLUT, 2); @@ -1220,15 +1352,22 @@ BOOL ReadLUT_A2B(LPLCMSICCPROFILE Icc, LPLUT NewLUT, size_t BaseOffset, icTagSig // V4 stuff. LutBtoA type static -BOOL ReadLUT_B2A(LPLCMSICCPROFILE Icc, LPLUT NewLUT, size_t BaseOffset, icTagSignature sig) +LCMSBOOL ReadLUT_B2A(LPLCMSICCPROFILE Icc, LPLUT NewLUT, size_t BaseOffset, icTagSignature sig) { icLutBtoA LUT16; - Icc ->Read(&LUT16, sizeof(icLutBtoA), 1, Icc); + if (Icc ->Read(&LUT16, sizeof(icLutBtoA), 1, Icc) != 1) return FALSE; NewLUT -> InputChan = LUT16.inputChan; NewLUT -> OutputChan = LUT16.outputChan; + // Validate the NewLUT here to avoid excessive number of channels + // (leading to stack-based buffer overflow in ReadSetOfCurves). + // Needs revalidation after table size is filled in. + if (!_cmsValidateLUT(NewLUT)) { + return FALSE; + } + AdjustEndianess32((LPBYTE) &LUT16.offsetB); AdjustEndianess32((LPBYTE) &LUT16.offsetMat); AdjustEndianess32((LPBYTE) &LUT16.offsetM); @@ -1242,7 +1381,6 @@ BOOL ReadLUT_B2A(LPLCMSICCPROFILE Icc, LPLUT NewLUT, size_t BaseOffset, icTagSi if (LUT16.offsetMat != 0) ReadMatrixOffset(Icc, BaseOffset + LUT16.offsetMat, NewLUT, LUT_HASMATRIX3); - if (LUT16.offsetM != 0) ReadSetOfCurves(Icc, BaseOffset + LUT16.offsetM, NewLUT, 3); @@ -1294,7 +1432,7 @@ LPLUT LCMSEXPORT cmsReadICCLut(cmsHPROFILE hProfile, icTagSignature sig) // If is in memory, the LUT is already there, so throw a copy - if (!Icc -> stream) { + if (Icc -> TagPtrs[n]) { return cmsDupLUT((LPLUT) Icc ->TagPtrs[n]); } @@ -1308,8 +1446,8 @@ LPLUT LCMSEXPORT cmsReadICCLut(cmsHPROFILE hProfile, icTagSignature sig) NewLUT = cmsAllocLUT(); - if (!NewLUT) - { + if (!NewLUT) { + cmsSignalError(LCMS_ERRC_ABORTED, "cmsAllocLUT() failed"); return NULL; } @@ -1317,11 +1455,29 @@ LPLUT LCMSEXPORT cmsReadICCLut(cmsHPROFILE hProfile, icTagSignature sig) switch (BaseType) { - case icSigLut8Type: ReadLUT8(Icc, NewLUT, sig); break; - case icSigLut16Type: ReadLUT16(Icc, NewLUT); break; + case icSigLut8Type: if (!ReadLUT8(Icc, NewLUT, sig)) { + cmsFreeLUT(NewLUT); + return NULL; + } + break; - case icSiglutAtoBType: ReadLUT_A2B(Icc, NewLUT, offset, sig); break; - case icSiglutBtoAType: ReadLUT_B2A(Icc, NewLUT, offset, sig); break; + case icSigLut16Type: if (!ReadLUT16(Icc, NewLUT)) { + cmsFreeLUT(NewLUT); + return NULL; + } + break; + + case icSiglutAtoBType: if (!ReadLUT_A2B(Icc, NewLUT, offset, sig)) { + cmsFreeLUT(NewLUT); + return NULL; + } + break; + + case icSiglutBtoAType: if (!ReadLUT_B2A(Icc, NewLUT, offset, sig)) { + cmsFreeLUT(NewLUT); + return NULL; + } + break; default: cmsSignalError(LCMS_ERRC_ABORTED, "Bad tag signature %lx found.", BaseType); cmsFreeLUT(NewLUT); @@ -1335,16 +1491,23 @@ LPLUT LCMSEXPORT cmsReadICCLut(cmsHPROFILE hProfile, icTagSignature sig) // Sets the language & country preferences. Used only in ICC 4.0 profiles -void LCMSEXPORT cmsSetLanguage(int LanguageCode, int CountryCode) +void LCMSEXPORT cmsSetLanguage(const char LanguageCode[4], const char CountryCode[4]) { - GlobalLanguageCode = LanguageCode; - GlobalCountryCode = CountryCode; + + int LanguageCodeInt = *(int *) LanguageCode; + int CountryCodeInt = *(int *) CountryCode; + + AdjustEndianess32((LPBYTE) &LanguageCodeInt); + AdjustEndianess32((LPBYTE) &CountryCodeInt); + + GlobalLanguageCode = LanguageCodeInt; + GlobalCountryCode = CountryCodeInt; } // Some tags (e.g, 'pseq') can have text tags embedded. This function -// handles such special case. +// handles such special case. Returns -1 on error, or the number of bytes left on success. static int ReadEmbeddedTextTag(LPLCMSICCPROFILE Icc, size_t size, char* Name, size_t size_max) @@ -1353,7 +1516,6 @@ int ReadEmbeddedTextTag(LPLCMSICCPROFILE Icc, size_t size, char* Name, size_t si BaseType = ReadBase(Icc); - size -= sizeof(icTagBase); switch (BaseType) { @@ -1365,50 +1527,54 @@ int ReadEmbeddedTextTag(LPLCMSICCPROFILE Icc, size_t size, char* Name, size_t si icUInt16Number ScriptCodeCode, Dummy; icUInt8Number ScriptCodeCount; - Icc ->Read(&AsciiCount, sizeof(icUInt32Number), 1, Icc); + if (Icc ->Read(&AsciiCount, sizeof(icUInt32Number), 1, Icc) != 1) return -1; - if (size < sizeof(icUInt32Number)) return (int) size; + if (size < sizeof(icUInt32Number)) return (int) size; size -= sizeof(icUInt32Number); AdjustEndianess32((LPBYTE) &AsciiCount); Icc ->Read(Name, 1, (AsciiCount >= size_max) ? (size_max-1) : AsciiCount, Icc); - if (size < AsciiCount) return (int) size; + if (size < AsciiCount) return (int) size; size -= AsciiCount; // Skip Unicode code - Icc ->Read(&UnicodeCode, sizeof(icUInt32Number), 1, Icc); - if (size < sizeof(icUInt32Number)) return (int) size; + if (Icc ->Read(&UnicodeCode, sizeof(icUInt32Number), 1, Icc) != 1) return -1; + if (size < sizeof(icUInt32Number)) return (int) size; size -= sizeof(icUInt32Number); - Icc ->Read(&UnicodeCount, sizeof(icUInt32Number), 1, Icc); - if (size < sizeof(icUInt32Number)) return (int) size; + if (Icc ->Read(&UnicodeCount, sizeof(icUInt32Number), 1, Icc) != 1) return -1; + if (size < sizeof(icUInt32Number)) return (int) size; size -= sizeof(icUInt32Number); AdjustEndianess32((LPBYTE) &UnicodeCount); if (UnicodeCount > size) return (int) size; - for (i=0; i < UnicodeCount; i++) - Icc ->Read(&Dummy, sizeof(icUInt16Number), 1, Icc); - - size -= UnicodeCount * sizeof(icUInt16Number); + for (i=0; i < UnicodeCount; i++) { + size_t nread = Icc ->Read(&Dummy, sizeof(icUInt16Number), 1, Icc); + if (nread != 1) return (int) size; + size -= sizeof(icUInt16Number); + } // Skip ScriptCode code - Icc ->Read(&ScriptCodeCode, sizeof(icUInt16Number), 1, Icc); + if (Icc ->Read(&ScriptCodeCode, sizeof(icUInt16Number), 1, Icc) != 1) return -1; size -= sizeof(icUInt16Number); - Icc ->Read(&ScriptCodeCount, sizeof(icUInt8Number), 1, Icc); + if (Icc ->Read(&ScriptCodeCount, sizeof(icUInt8Number), 1, Icc) != 1) return -1; size -= sizeof(icUInt8Number); + // Should remain 67 bytes as filler + if (size < 67) return (int) size; - for (i=0; i < 67; i++) - Icc ->Read(&Dummy, sizeof(icUInt8Number), 1, Icc); - - size -= 67; + for (i=0; i < 67; i++) { + size_t nread = Icc ->Read(&Dummy, sizeof(icUInt8Number), 1, Icc); + if (nread != 1) return (int) size; + size --; + } } break; @@ -1425,7 +1591,7 @@ int ReadEmbeddedTextTag(LPLCMSICCPROFILE Icc, size_t size, char* Name, size_t si size = size_max - 1; } - Icc -> Read(Name, 1, size, Icc); + if (Icc -> Read(Name, 1, size, Icc) != size) return -1; for (i=0; i < Missing; i++) Icc -> Read(&Dummy, 1, 1, Icc); @@ -1445,9 +1611,9 @@ int ReadEmbeddedTextTag(LPLCMSICCPROFILE Icc, size_t size, char* Name, size_t si wchar_t* wchar = L""; - Icc ->Read(&Count, sizeof(icUInt32Number), 1, Icc); + if (Icc ->Read(&Count, sizeof(icUInt32Number), 1, Icc) != 1) return -1; AdjustEndianess32((LPBYTE) &Count); - Icc ->Read(&RecLen, sizeof(icUInt32Number), 1, Icc); + if (Icc ->Read(&RecLen, sizeof(icUInt32Number), 1, Icc) != 1) return -1; AdjustEndianess32((LPBYTE) &RecLen); if (RecLen != 12) { @@ -1458,15 +1624,15 @@ int ReadEmbeddedTextTag(LPLCMSICCPROFILE Icc, size_t size, char* Name, size_t si for (i=0; i < Count; i++) { - Icc ->Read(&Language, sizeof(icUInt16Number), 1, Icc); + if (Icc ->Read(&Language, sizeof(icUInt16Number), 1, Icc) != 1) return -1; AdjustEndianess16((LPBYTE) &Language); - Icc ->Read(&Country, sizeof(icUInt16Number), 1, Icc); + if (Icc ->Read(&Country, sizeof(icUInt16Number), 1, Icc) != 1) return -1; AdjustEndianess16((LPBYTE) &Country); - Icc ->Read(&ThisLen, sizeof(icUInt32Number), 1, Icc); + if (Icc ->Read(&ThisLen, sizeof(icUInt32Number), 1, Icc) != 1) return -1; AdjustEndianess32((LPBYTE) &ThisLen); - Icc ->Read(&ThisOffset, sizeof(icUInt32Number), 1, Icc); + if (Icc ->Read(&ThisOffset, sizeof(icUInt32Number), 1, Icc) != 1) return -1; AdjustEndianess32((LPBYTE) &ThisOffset); if (Language == GlobalLanguageCode || Offset == 0) { @@ -1492,14 +1658,18 @@ int ReadEmbeddedTextTag(LPLCMSICCPROFILE Icc, size_t size, char* Name, size_t si for (i=0; i < Offset; i++) { char Discard; - - Icc ->Read(&Discard, 1, 1, Icc); + if (Icc ->Read(&Discard, 1, 1, Icc) != 1) return -1; } - wchar = (wchar_t*) malloc(Len+2); + + // Bound len + if (Len < 0) Len = 0; + if (Len > 20*1024) Len = 20 * 1024; + + wchar = (wchar_t*) _cmsMalloc(Len*sizeof(wchar_t)+2); if (!wchar) return -1; - Icc ->Read(wchar, 1, Len, Icc); + if (Icc ->Read(wchar, 1, Len, Icc) != Len) return -1; AdjustEndianessArray16((LPWORD) wchar, Len / 2); wchar[Len / 2] = L'\0'; @@ -1509,7 +1679,7 @@ int ReadEmbeddedTextTag(LPLCMSICCPROFILE Icc, size_t size, char* Name, size_t si Name[0] = 0; // Error } - free((void*) wchar); + _cmsFree((void*) wchar); } break; @@ -1522,8 +1692,7 @@ int ReadEmbeddedTextTag(LPLCMSICCPROFILE Icc, size_t size, char* Name, size_t si } -// Take an ASCII item. Takes at most LCMS_DESC_MAX - +// Take an ASCII item. Takes at most size_max bytes int LCMSEXPORT cmsReadICCTextEx(cmsHPROFILE hProfile, icTagSignature sig, char *Name, size_t size_max) { @@ -1535,19 +1704,27 @@ int LCMSEXPORT cmsReadICCTextEx(cmsHPROFILE hProfile, icTagSignature sig, char * if (n < 0) return -1; - if (!Icc -> stream) { + size = Icc -> TagSizes[n]; + + if (Icc -> TagPtrs[n]) { + + if (size > size_max) + size = size_max; + + CopyMemory(Name, Icc -> TagPtrs[n], size); - CopyMemory(Name, Icc -> TagPtrs[n], Icc -> TagSizes[n]); return (int) Icc -> TagSizes[n]; } offset = Icc -> TagOffsets[n]; - size = Icc -> TagSizes[n]; + if (Icc -> Seek(Icc, offset)) return -1; - return ReadEmbeddedTextTag(Icc, size, Name, size_max); + if (ReadEmbeddedTextTag(Icc, size, Name, size_max) < 0) return -1; + + return size; } // Keep compatibility with older versions @@ -1561,7 +1738,7 @@ int LCMSEXPORT cmsReadICCText(cmsHPROFILE hProfile, icTagSignature sig, char *Te // Take an XYZ item static -int ReadICCXYZ(cmsHPROFILE hProfile, icTagSignature sig, LPcmsCIEXYZ Value, BOOL lIsFatal) +int ReadICCXYZ(cmsHPROFILE hProfile, icTagSignature sig, LPcmsCIEXYZ Value, LCMSBOOL lIsFatal) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; icTagTypeSignature BaseType; @@ -1573,7 +1750,7 @@ int ReadICCXYZ(cmsHPROFILE hProfile, icTagSignature sig, LPcmsCIEXYZ Value, BOOL if (n < 0) return -1; - if (!Icc -> stream) { + if (Icc -> TagPtrs[n]) { CopyMemory(Value, Icc -> TagPtrs[n], Icc -> TagSizes[n]); return (int) Icc -> TagSizes[n]; @@ -1628,7 +1805,7 @@ int ReadICCXYZArray(cmsHPROFILE hProfile, icTagSignature sig, LPMAT3 v) if (n < 0) return -1; // Not found - if (!Icc -> stream) { + if (Icc -> TagPtrs[n]) { CopyMemory(v, Icc -> TagPtrs[n], Icc -> TagSizes[n]); return (int) Icc -> TagSizes[n]; @@ -1677,7 +1854,7 @@ int ReadICCXYZArray(cmsHPROFILE hProfile, icTagSignature sig, LPMAT3 v) // Primaries are to be in xyY notation -BOOL LCMSEXPORT cmsTakeColorants(LPcmsCIEXYZTRIPLE Dest, cmsHPROFILE hProfile) +LCMSBOOL LCMSEXPORT cmsTakeColorants(LPcmsCIEXYZTRIPLE Dest, cmsHPROFILE hProfile) { if (ReadICCXYZ(hProfile, icSigRedColorantTag, &Dest -> Red, TRUE) < 0) return FALSE; if (ReadICCXYZ(hProfile, icSigGreenColorantTag, &Dest -> Green, TRUE) < 0) return FALSE; @@ -1687,7 +1864,7 @@ BOOL LCMSEXPORT cmsTakeColorants(LPcmsCIEXYZTRIPLE Dest, cmsHPROFILE hProfile) } -BOOL cmsReadICCMatrixRGB2XYZ(LPMAT3 r, cmsHPROFILE hProfile) +LCMSBOOL cmsReadICCMatrixRGB2XYZ(LPMAT3 r, cmsHPROFILE hProfile) { cmsCIEXYZTRIPLE Primaries; @@ -1704,7 +1881,7 @@ BOOL cmsReadICCMatrixRGB2XYZ(LPMAT3 r, cmsHPROFILE hProfile) // Always return a suitable matrix -BOOL cmsReadChromaticAdaptationMatrix(LPMAT3 r, cmsHPROFILE hProfile) +LCMSBOOL cmsReadChromaticAdaptationMatrix(LPMAT3 r, cmsHPROFILE hProfile) { if (ReadICCXYZArray(hProfile, icSigChromaticAdaptationTag, r) < 0) { @@ -1741,7 +1918,7 @@ LPGAMMATABLE LCMSEXPORT cmsReadICCGamma(cmsHPROFILE hProfile, icTagSignature sig if (n < 0) return NULL; - if (!Icc -> stream) { + if (Icc -> TagPtrs[n]) { return cmsDupGamma((LPGAMMATABLE) Icc -> TagPtrs[n]); } @@ -1769,7 +1946,7 @@ LPGAMMATABLE LCMSEXPORT cmsReadICCGammaReversed(cmsHPROFILE hProfile, icTagSigna if (n < 0) return NULL; - if (!Icc -> stream) { + if (Icc -> TagPtrs[n]) { return cmsReverseGamma(256, (LPGAMMATABLE) Icc -> TagPtrs[n]); } @@ -1785,7 +1962,7 @@ LPGAMMATABLE LCMSEXPORT cmsReadICCGammaReversed(cmsHPROFILE hProfile, icTagSigna // Check Named color header static -BOOL CheckHeader(LPcmsNAMEDCOLORLIST v, icNamedColor2* nc2) +LCMSBOOL CheckHeader(LPcmsNAMEDCOLORLIST v, icNamedColor2* nc2) { if (v ->Prefix[0] == 0 && v ->Suffix[0] == 0 && v ->ColorantCount == 0) return TRUE; @@ -1809,13 +1986,13 @@ int cmsReadICCnamedColorList(cmsHTRANSFORM xform, cmsHPROFILE hProfile, icTagSig if (n < 0) return 0; - if (!Icc -> stream) { + if (Icc -> TagPtrs[n]) { // This replaces actual named color list. size_t size = Icc -> TagSizes[n]; if (v ->NamedColorList) cmsFreeNamedColorList(v ->NamedColorList); - v -> NamedColorList = (LPcmsNAMEDCOLORLIST) malloc(size); + v -> NamedColorList = (LPcmsNAMEDCOLORLIST) _cmsMalloc(size); CopyMemory(v -> NamedColorList, Icc ->TagPtrs[n], size); return v ->NamedColorList->nColors; } @@ -1844,7 +2021,7 @@ int cmsReadICCnamedColorList(cmsHTRANSFORM xform, cmsHPROFILE hProfile, icTagSig icNamedColor2 nc2; unsigned int i, j; - Icc -> Read(&nc2, sizeof(icNamedColor2) - SIZEOF_UINT8_ALIGNED, 1, Icc); + if (Icc -> Read(&nc2, sizeof(icNamedColor2) - SIZEOF_UINT8_ALIGNED, 1, Icc) != 1) return 0; AdjustEndianess32((LPBYTE) &nc2.vendorFlag); AdjustEndianess32((LPBYTE) &nc2.count); AdjustEndianess32((LPBYTE) &nc2.nDeviceCoords); @@ -1854,6 +2031,11 @@ int cmsReadICCnamedColorList(cmsHTRANSFORM xform, cmsHPROFILE hProfile, icTagSig return 0; } + if (nc2.nDeviceCoords > MAXCHANNELS) { + cmsSignalError(LCMS_ERRC_WARNING, "Too many device coordinates."); + return 0; + } + strncpy(v ->NamedColorList->Prefix, (const char*) nc2.prefix, 32); strncpy(v ->NamedColorList->Suffix, (const char*) nc2.suffix, 32); v ->NamedColorList->Prefix[32] = v->NamedColorList->Suffix[32] = 0; @@ -1900,7 +2082,8 @@ int cmsReadICCnamedColorList(cmsHTRANSFORM xform, cmsHPROFILE hProfile, icTagSig LPcmsNAMEDCOLORLIST LCMSEXPORT cmsReadColorantTable(cmsHPROFILE hProfile, icTagSignature sig) { - icInt32Number n, Count, i; + icInt32Number n; + icUInt32Number Count, i; size_t offset; icTagTypeSignature BaseType; LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; @@ -1910,10 +2093,12 @@ LPcmsNAMEDCOLORLIST LCMSEXPORT cmsReadColorantTable(cmsHPROFILE hProfile, icTagS if (n < 0) return NULL; // Not found - if (!Icc -> stream) { + if (Icc -> TagPtrs[n]) { size_t size = Icc -> TagSizes[n]; - void* v = malloc(size); + void* v = _cmsMalloc(size); + + if (v == NULL) return NULL; CopyMemory(v, Icc -> TagPtrs[n], size); return (LPcmsNAMEDCOLORLIST) v; } @@ -1932,13 +2117,17 @@ LPcmsNAMEDCOLORLIST LCMSEXPORT cmsReadColorantTable(cmsHPROFILE hProfile, icTagS } - Icc ->Read(&Count, sizeof(icUInt32Number), 1, Icc); + if (Icc ->Read(&Count, sizeof(icUInt32Number), 1, Icc) != 1) return NULL; AdjustEndianess32((LPBYTE) &Count); + if (Count > MAXCHANNELS) { + cmsSignalError(LCMS_ERRC_ABORTED, "Too many colorants '%lx'", Count); + return NULL; + } + List = cmsAllocNamedColorList(Count); for (i=0; i < Count; i++) { - if (!Icc ->Read(List->List[i].Name, 1, 32 , Icc)) goto Error; if (!Icc ->Read(List->List[i].PCS, sizeof(icUInt16Number), 3, Icc)) goto Error; AdjustEndianessArray16(List->List[i].PCS, 3); @@ -1965,7 +2154,7 @@ const char* LCMSEXPORT cmsTakeManufacturer(cmsHPROFILE hProfile) if (cmsIsTag(hProfile, icSigDeviceMfgDescTag)) { - cmsReadICCText(hProfile, icSigDeviceMfgDescTag, Manufacturer); + cmsReadICCTextEx(hProfile, icSigDeviceMfgDescTag, Manufacturer, LCMS_DESC_MAX); } return Manufacturer; @@ -1982,7 +2171,7 @@ const char* LCMSEXPORT cmsTakeModel(cmsHPROFILE hProfile) if (cmsIsTag(hProfile, icSigDeviceModelDescTag)) { - cmsReadICCText(hProfile, icSigDeviceModelDescTag, Model); + cmsReadICCTextEx(hProfile, icSigDeviceModelDescTag, Model, LCMS_DESC_MAX); } return Model; @@ -1995,10 +2184,9 @@ const char* LCMSEXPORT cmsTakeCopyright(cmsHPROFILE hProfile) static char Copyright[LCMS_DESC_MAX] = ""; Copyright[0] = 0; - if (cmsIsTag(hProfile, icSigCopyrightTag)) { - cmsReadICCText(hProfile, icSigCopyrightTag, Copyright); + cmsReadICCTextEx(hProfile, icSigCopyrightTag, Copyright, LCMS_DESC_MAX); } return Copyright; @@ -2009,7 +2197,7 @@ const char* LCMSEXPORT cmsTakeCopyright(cmsHPROFILE hProfile) const char* LCMSEXPORT cmsTakeProductName(cmsHPROFILE hProfile) { - static char Name[2048]; + static char Name[LCMS_DESC_MAX*2+4]; char Manufacturer[LCMS_DESC_MAX], Model[LCMS_DESC_MAX]; Name[0] = '\0'; @@ -2017,19 +2205,19 @@ const char* LCMSEXPORT cmsTakeProductName(cmsHPROFILE hProfile) if (cmsIsTag(hProfile, icSigDeviceMfgDescTag)) { - cmsReadICCText(hProfile, icSigDeviceMfgDescTag, Manufacturer); + cmsReadICCTextEx(hProfile, icSigDeviceMfgDescTag, Manufacturer, LCMS_DESC_MAX); } if (cmsIsTag(hProfile, icSigDeviceModelDescTag)) { - cmsReadICCText(hProfile, icSigDeviceModelDescTag, Model); + cmsReadICCTextEx(hProfile, icSigDeviceModelDescTag, Model, LCMS_DESC_MAX); } if (!Manufacturer[0] && !Model[0]) { if (cmsIsTag(hProfile, icSigProfileDescriptionTag)) { - cmsReadICCText(hProfile, icSigProfileDescriptionTag, Name); + cmsReadICCTextEx(hProfile, icSigProfileDescriptionTag, Name, LCMS_DESC_MAX); return Name; } else return "{no name}"; @@ -2129,7 +2317,7 @@ const char* LCMSEXPORT cmsTakeProductInfo(cmsHPROFILE hProfile) // Extract the target data as a big string. Does not signal if tag is not present. -BOOL LCMSEXPORT cmsTakeCharTargetData(cmsHPROFILE hProfile, char** Data, size_t* len) +LCMSBOOL LCMSEXPORT cmsTakeCharTargetData(cmsHPROFILE hProfile, char** Data, size_t* len) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; int n; @@ -2142,7 +2330,11 @@ BOOL LCMSEXPORT cmsTakeCharTargetData(cmsHPROFILE hProfile, char** Data, size_t* *len = Icc -> TagSizes[n]; - *Data = (char*) malloc(*len + 1); // Plus zero marker + + // Make sure that is reasonable (600K) + if (*len > 600*1024) *len = 600*1024; + + *Data = (char*) _cmsMalloc(*len + 1); // Plus zero marker if (!*Data) { @@ -2162,7 +2354,7 @@ BOOL LCMSEXPORT cmsTakeCharTargetData(cmsHPROFILE hProfile, char** Data, size_t* -BOOL LCMSEXPORT cmsTakeCalibrationDateTime(struct tm *Dest, cmsHPROFILE hProfile) +LCMSBOOL LCMSEXPORT cmsTakeCalibrationDateTime(struct tm *Dest, cmsHPROFILE hProfile) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; int n; @@ -2170,8 +2362,8 @@ BOOL LCMSEXPORT cmsTakeCalibrationDateTime(struct tm *Dest, cmsHPROFILE hProfile n = _cmsSearchTag(Icc, icSigCalibrationDateTimeTag, FALSE); if (n < 0) return FALSE; - if (!Icc ->stream) - { + if (Icc ->TagPtrs[n]) { + CopyMemory(Dest, Icc ->TagPtrs[n], sizeof(struct tm)); } else @@ -2212,9 +2404,10 @@ LPcmsSEQ LCMSEXPORT cmsReadProfileSequenceDescription(cmsHPROFILE hProfile) size = Icc -> TagSizes[n]; if (size < 12) return NULL; - if (!Icc -> stream) { + if (Icc -> TagPtrs[n]) { - OutSeq = (LPcmsSEQ) malloc(size); + OutSeq = (LPcmsSEQ) _cmsMalloc(size); + if (OutSeq == NULL) return NULL; CopyMemory(OutSeq, Icc ->TagPtrs[n], size); return OutSeq; } @@ -2231,8 +2424,13 @@ LPcmsSEQ LCMSEXPORT cmsReadProfileSequenceDescription(cmsHPROFILE hProfile) Icc ->Read(&Count, sizeof(icUInt32Number), 1, Icc); AdjustEndianess32((LPBYTE) &Count); + if (Count > 1000) { + return NULL; + } + size = sizeof(int) + Count * sizeof(cmsPSEQDESC); - OutSeq = (LPcmsSEQ) malloc(size); + OutSeq = (LPcmsSEQ) _cmsMalloc(size); + if (OutSeq == NULL) return NULL; OutSeq ->n = Count; @@ -2268,181 +2466,11 @@ LPcmsSEQ LCMSEXPORT cmsReadProfileSequenceDescription(cmsHPROFILE hProfile) void LCMSEXPORT cmsFreeProfileSequenceDescription(LPcmsSEQ pseq) { if (pseq) - free(pseq); + _cmsFree(pseq); } -// Extended gamut -- an HP extension - - -LPcmsGAMUTEX LCMSEXPORT cmsReadExtendedGamut(cmsHPROFILE hProfile, int index) -{ - LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; - size_t size, offset; - icUInt32Number off_samp, off_desc, off_vc; - int n; - icTagTypeSignature BaseType; - icColorSpaceSignature CoordSig; - icUInt16Number Method, Usage; - icUInt32Number GamutCount, SamplesCount; - LPcmsGAMUTEX gex; - size_t Offsets[256]; - size_t i, Actual, Loc; - icS15Fixed16Number Num; - icUInt16Number Surround; - - - n = _cmsSearchTag(Icc, icSigHPGamutDescTag, FALSE); - if (n < 0) return NULL; - - if (!Icc ->stream) return NULL; // In memory is not supported - - // Read the header - - offset = Icc -> TagOffsets[n]; - - if (Icc -> Seek(Icc, offset)) - return NULL; - - // Here is the beginning of tag - Actual = Icc ->Tell(Icc); - - - BaseType = ReadBase(Icc); - - if (BaseType != icSigHPGamutDescType) { - cmsSignalError(LCMS_ERRC_ABORTED, "Bad tag signature '%lx' found.", BaseType); - return NULL; - } - - - // Read the gamut descriptors count - Icc ->Read(&GamutCount, sizeof(icUInt32Number), 1, Icc); - AdjustEndianess32((LPBYTE) &GamutCount); - - - if (GamutCount >= 256) { - cmsSignalError(LCMS_ERRC_ABORTED, "Too many gamut structures '%d'.", GamutCount); - return NULL; - } - - // Read the directory - - for (i=0; i < GamutCount; i++) { - - Icc ->Read(&Offsets[i], sizeof(icUInt32Number), 1, Icc); - AdjustEndianess32((LPBYTE) &Offsets[i]); - } - - - // Is there such element? - if (index >= (int) GamutCount) return NULL; - Loc = Actual + Offsets[index]; - - - // Go to specified index - if (Icc -> Seek(Icc, Loc)) - return NULL; - - - // Read all members - Icc ->Read(&CoordSig, sizeof(icColorSpaceSignature), 1, Icc); - AdjustEndianess32((LPBYTE) &CoordSig); - - Icc ->Read(&Method, sizeof(icUInt16Number), 1, Icc); - AdjustEndianess16((LPBYTE) &Method); - - Icc ->Read(&Usage, sizeof(icUInt16Number), 1, Icc); - AdjustEndianess16((LPBYTE) &Usage); - - Icc ->Read(&SamplesCount, sizeof(icUInt32Number), 1, Icc); - AdjustEndianess32((LPBYTE) &SamplesCount); - - Icc ->Read(&off_samp, sizeof(icUInt32Number), 1, Icc); - AdjustEndianess32((LPBYTE) &off_samp); - - Icc ->Read(&off_desc, sizeof(icUInt32Number), 1, Icc); - AdjustEndianess32((LPBYTE) &off_desc); - - Icc ->Read(&off_vc, sizeof(icUInt32Number), 1, Icc); - AdjustEndianess32((LPBYTE) &off_vc); - - - size = sizeof(cmsGAMUTEX) + (SamplesCount - 1) * sizeof(double); - - gex = (LPcmsGAMUTEX) malloc(size); - if (gex == NULL) return NULL; - - - gex ->CoordSig = CoordSig; - gex ->Method = Method; - gex ->Usage = Usage; - gex ->Count = SamplesCount; - - - // Read data - if (Icc -> Seek(Icc, Loc + off_samp)) - return NULL; - - for (i=0; i < SamplesCount; i++) { - Icc -> Read(&Num, sizeof(icS15Fixed16Number), 1, Icc); - gex ->Data[i] = Convert15Fixed16(Num); - } - - - // Read mluc - if (Icc -> Seek(Icc, Loc + off_desc)) { - - free(gex); - return NULL; - } - - ReadEmbeddedTextTag(Icc, 256, gex ->Description, LCMS_DESC_MAX); - - - // Read viewing conditions - if (Icc -> Seek(Icc, Loc + off_vc)) { - free(gex); - return NULL; - } - - - Icc -> Read(&Num, sizeof(icS15Fixed16Number), 1, Icc); - gex ->Vc.whitePoint.X = Convert15Fixed16(Num); - - Icc -> Read(&Num, sizeof(icS15Fixed16Number), 1, Icc); - gex ->Vc.whitePoint.Y = Convert15Fixed16(Num); - - Icc -> Read(&Num, sizeof(icS15Fixed16Number), 1, Icc); - gex ->Vc.whitePoint.Z = Convert15Fixed16(Num); - - Icc -> Read(&Num, sizeof(icS15Fixed16Number), 1, Icc); - gex ->Vc.La = Convert15Fixed16(Num); - - Icc -> Read(&Num, sizeof(icS15Fixed16Number), 1, Icc); - gex ->Vc.Yb = Convert15Fixed16(Num); - - Icc -> Read(&Num, sizeof(icS15Fixed16Number), 1, Icc); - gex ->Vc.D_value = Convert15Fixed16(Num); - - Icc -> Read(&Surround, sizeof(icUInt16Number), 1, Icc); - AdjustEndianess16((LPBYTE) &Surround); - gex ->Vc.surround = Surround; - - - // All OK - return gex; - -} - - - -void LCMSEXPORT cmsFreeExtendedGamut(LPcmsGAMUTEX gex) -{ - if (gex) - free(gex); -} // Read a few tags that are hardly required @@ -2564,6 +2592,7 @@ cmsHPROFILE LCMSEXPORT cmsOpenProfileFromFile(const char *lpFileName, const char NewIcc = (LPLCMSICCPROFILE) (LPSTR) hEmpty; NewIcc -> IsWrite = TRUE; strncpy(NewIcc ->PhysicalFile, lpFileName, MAX_PATH-1); + NewIcc ->PhysicalFile[MAX_PATH-1] = 0; // Save LUT as 8 bit @@ -2609,14 +2638,14 @@ cmsHPROFILE LCMSEXPORT cmsOpenProfileFromMem(LPVOID MemPtr, DWORD dwSize) -BOOL LCMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile) +LCMSBOOL LCMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; - BOOL rc = TRUE; + LCMSBOOL rc = TRUE; + icInt32Number i; if (!Icc) return FALSE; - // Was open in write mode? if (Icc ->IsWrite) { @@ -2624,21 +2653,15 @@ BOOL LCMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile) rc = _cmsSaveProfile(hProfile, Icc ->PhysicalFile); } - - if (Icc -> stream == NULL) { // Was a memory (i.e. not serialized) profile? - - - icInt32Number i; // Yes, free tags - - for (i=0; i < Icc -> TagCount; i++) { + for (i=0; i < Icc -> TagCount; i++) { if (Icc -> TagPtrs[i]) free(Icc -> TagPtrs[i]); - } - } - else Icc -> Close(Icc); // No, close the stream + if (Icc -> stream != NULL) { // Was a memory (i.e. not serialized) profile? + Icc -> Close(Icc); // No, close the stream + } free(Icc); // Free placeholder memory @@ -2652,11 +2675,11 @@ BOOL LCMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile) static -BOOL SaveWordsTable(int nEntries, LPWORD Tab, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveWordsTable(int nEntries, LPWORD Tab, LPLCMSICCPROFILE Icc) { size_t nTabSize = sizeof(WORD) * nEntries; - LPWORD PtrW = (LPWORD) malloc(nTabSize); - BOOL rc; + LPWORD PtrW = (LPWORD) _cmsMalloc(nTabSize); + LCMSBOOL rc; if (!PtrW) return FALSE; CopyMemory(PtrW, Tab, nTabSize); @@ -2672,7 +2695,7 @@ BOOL SaveWordsTable(int nEntries, LPWORD Tab, LPLCMSICCPROFILE Icc) // Saves profile header static -BOOL SaveHeader(LPLCMSICCPROFILE Icc) +LCMSBOOL SaveHeader(LPLCMSICCPROFILE Icc) { icHeader Header; time_t now = time(NULL); @@ -2727,7 +2750,7 @@ BOOL SaveHeader(LPLCMSICCPROFILE Icc) // Setup base marker static -BOOL SetupBase(icTagTypeSignature sig, LPLCMSICCPROFILE Icc) +LCMSBOOL SetupBase(icTagTypeSignature sig, LPLCMSICCPROFILE Icc) { icTagBase Base; @@ -2737,10 +2760,10 @@ BOOL SetupBase(icTagTypeSignature sig, LPLCMSICCPROFILE Icc) } -// Store an XYZ tag +// Store a XYZ tag static -BOOL SaveXYZNumber(LPcmsCIEXYZ Value, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveXYZNumber(LPcmsCIEXYZ Value, LPLCMSICCPROFILE Icc) { icXYZNumber XYZ; @@ -2756,72 +2779,97 @@ BOOL SaveXYZNumber(LPcmsCIEXYZ Value, LPLCMSICCPROFILE Icc) } +// Store a XYZ array. + +static +LCMSBOOL SaveXYZArray(int n, LPcmsCIEXYZ Value, LPLCMSICCPROFILE Icc) +{ + int i; + icXYZNumber XYZ; + + if (!SetupBase(icSigS15Fixed16ArrayType, Icc)) return FALSE; + + for (i=0; i < n; i++) { + + XYZ.X = TransportValue32(DOUBLE_TO_FIXED(Value -> X)); + XYZ.Y = TransportValue32(DOUBLE_TO_FIXED(Value -> Y)); + XYZ.Z = TransportValue32(DOUBLE_TO_FIXED(Value -> Z)); + + if (!Icc -> Write(Icc, sizeof(icXYZNumber), &XYZ)) return FALSE; + + Value++; + } + + return TRUE; +} + + // Save a gamma structure as a table static -BOOL SaveGammaTable(LPGAMMATABLE Gamma, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveGammaTable(LPGAMMATABLE Gamma, LPLCMSICCPROFILE Icc) { - icInt32Number Count; + icInt32Number Count; - if (!SetupBase(icSigCurveType, Icc)) return FALSE; + if (!SetupBase(icSigCurveType, Icc)) return FALSE; - Count = TransportValue32(Gamma->nEntries); + Count = TransportValue32(Gamma->nEntries); - if (!Icc ->Write(Icc, sizeof(icInt32Number), &Count)) return FALSE; + if (!Icc ->Write(Icc, sizeof(icInt32Number), &Count)) return FALSE; - return SaveWordsTable(Gamma->nEntries, Gamma ->GammaTable, Icc); + return SaveWordsTable(Gamma->nEntries, Gamma ->GammaTable, Icc); } // Save a gamma structure as a one-value static -BOOL SaveGammaOneValue(LPGAMMATABLE Gamma, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveGammaOneValue(LPGAMMATABLE Gamma, LPLCMSICCPROFILE Icc) { - icInt32Number Count; - Fixed32 GammaFixed32; - WORD GammaFixed8; + icInt32Number Count; + Fixed32 GammaFixed32; + WORD GammaFixed8; - if (!SetupBase(icSigCurveType, Icc)) return FALSE; + if (!SetupBase(icSigCurveType, Icc)) return FALSE; - Count = TransportValue32(1); - if (!Icc ->Write(Icc, sizeof(icInt32Number), &Count)) return FALSE; + Count = TransportValue32(1); + if (!Icc ->Write(Icc, sizeof(icInt32Number), &Count)) return FALSE; - GammaFixed32 = DOUBLE_TO_FIXED(Gamma ->Seed.Params[0]); - GammaFixed8 = (WORD) ((GammaFixed32 >> 8) & 0xFFFF); - GammaFixed8 = TransportValue16(GammaFixed8); + GammaFixed32 = DOUBLE_TO_FIXED(Gamma ->Seed.Params[0]); + GammaFixed8 = (WORD) ((GammaFixed32 >> 8) & 0xFFFF); + GammaFixed8 = TransportValue16(GammaFixed8); - return Icc ->Write(Icc, sizeof(icInt16Number), &GammaFixed8); + return Icc ->Write(Icc, sizeof(icInt16Number), &GammaFixed8); } // Save a gamma structure as a parametric gamma static -BOOL SaveGammaParametric(LPGAMMATABLE Gamma, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveGammaParametric(LPGAMMATABLE Gamma, LPLCMSICCPROFILE Icc) { - icUInt16Number Type, Reserved; - int i, nParams; - int ParamsByType[] = { 1, 3, 4, 5, 7 }; + icUInt16Number Type, Reserved; + int i, nParams; + int ParamsByType[] = { 1, 3, 4, 5, 7 }; - if (!SetupBase(icSigParametricCurveType, Icc)) return FALSE; + if (!SetupBase(icSigParametricCurveType, Icc)) return FALSE; - nParams = ParamsByType[Gamma -> Seed.Type]; + nParams = ParamsByType[Gamma -> Seed.Type]; - Type = (icUInt16Number) TransportValue16((WORD) Gamma -> Seed. Type); - Reserved = (icUInt16Number) TransportValue16((WORD) 0); + Type = (icUInt16Number) TransportValue16((WORD) Gamma -> Seed. Type); + Reserved = (icUInt16Number) TransportValue16((WORD) 0); - Icc -> Write(Icc, sizeof(icInt16Number), &Type); - Icc -> Write(Icc, sizeof(icUInt16Number), &Reserved); + Icc -> Write(Icc, sizeof(icInt16Number), &Type); + Icc -> Write(Icc, sizeof(icUInt16Number), &Reserved); - for (i=0; i < nParams; i++) { + for (i=0; i < nParams; i++) { - icInt32Number val = TransportValue32(DOUBLE_TO_FIXED(Gamma -> Seed.Params[i])); - Icc ->Write(Icc, sizeof(icInt32Number), &val); - } + icInt32Number val = TransportValue32(DOUBLE_TO_FIXED(Gamma -> Seed.Params[i])); + Icc ->Write(Icc, sizeof(icInt32Number), &val); + } - return TRUE; + return TRUE; } @@ -2829,29 +2877,29 @@ BOOL SaveGammaParametric(LPGAMMATABLE Gamma, LPLCMSICCPROFILE Icc) // Save a gamma table static -BOOL SaveGamma(LPGAMMATABLE Gamma, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveGamma(LPGAMMATABLE Gamma, LPLCMSICCPROFILE Icc) { - // Is the gamma curve type supported by ICC format? + // Is the gamma curve type supported by ICC format? - if (Gamma -> Seed.Type < 0 || Gamma -> Seed.Type > 5 || + if (Gamma -> Seed.Type < 0 || Gamma -> Seed.Type > 5 || - // has been modified by user? + // has been modified by user? - _cmsCrc32OfGammaTable(Gamma) != Gamma -> Seed.Crc32) { + _cmsCrc32OfGammaTable(Gamma) != Gamma -> Seed.Crc32) { - return SaveGammaTable(Gamma, Icc); - } + return SaveGammaTable(Gamma, Icc); + } - if (Gamma -> Seed.Type == 1) return SaveGammaOneValue(Gamma, Icc); + if (Gamma -> Seed.Type == 1) return SaveGammaOneValue(Gamma, Icc); - // Only v4 profiles are allowed to hold parametric curves + // Only v4 profiles are allowed to hold parametric curves - if (cmsGetProfileICCversion((cmsHPROFILE) Icc) >= 0x4000000) - return SaveGammaParametric(Gamma, Icc); + if (cmsGetProfileICCversion((cmsHPROFILE) Icc) >= 0x4000000) + return SaveGammaParametric(Gamma, Icc); - // Defaults to save as table + // Defaults to save as table - return SaveGammaTable(Gamma, Icc); + return SaveGammaTable(Gamma, Icc); } @@ -2861,7 +2909,7 @@ BOOL SaveGamma(LPGAMMATABLE Gamma, LPLCMSICCPROFILE Icc) // Save an DESC Tag static -BOOL SaveDescription(const char *Text, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveDescription(const char *Text, LPLCMSICCPROFILE Icc) { icUInt32Number len, Count, TotalSize, AlignedSize; @@ -2893,6 +2941,11 @@ BOOL SaveDescription(const char *Text, LPLCMSICCPROFILE Icc) if (!Icc ->Write(Icc, len, (LPVOID)Text)) return FALSE; AlignedSize -= len; + if (AlignedSize < 0) + AlignedSize = 0; + if (AlignedSize > 255) + AlignedSize = 255; + ZeroMemory(Filler, AlignedSize); if (!Icc ->Write(Icc, AlignedSize, Filler)) return FALSE; @@ -2902,7 +2955,7 @@ BOOL SaveDescription(const char *Text, LPLCMSICCPROFILE Icc) // Save an ASCII Tag static -BOOL SaveText(const char *Text, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveText(const char *Text, LPLCMSICCPROFILE Icc) { size_t len = strlen(Text) + 1; @@ -2915,7 +2968,7 @@ BOOL SaveText(const char *Text, LPLCMSICCPROFILE Icc) // Save one of these new chromaticity values static -BOOL SaveOneChromaticity(double x, double y, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveOneChromaticity(double x, double y, LPLCMSICCPROFILE Icc) { Fixed32 xf, yf; @@ -2932,7 +2985,7 @@ BOOL SaveOneChromaticity(double x, double y, LPLCMSICCPROFILE Icc) // New tag added in Addendum II of old spec. static -BOOL SaveChromaticities(LPcmsCIExyYTRIPLE chrm, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveChromaticities(LPcmsCIExyYTRIPLE chrm, LPLCMSICCPROFILE Icc) { WORD nChans, Table; @@ -2952,7 +3005,7 @@ BOOL SaveChromaticities(LPcmsCIExyYTRIPLE chrm, LPLCMSICCPROFILE Icc) static -BOOL SaveSequenceDescriptionTag(LPcmsSEQ seq, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveSequenceDescriptionTag(LPcmsSEQ seq, LPLCMSICCPROFILE Icc) { icUInt32Number nSeqs; icDescStruct DescStruct; @@ -2989,7 +3042,7 @@ BOOL SaveSequenceDescriptionTag(LPcmsSEQ seq, LPLCMSICCPROFILE Icc) // Saves a timestamp tag static -BOOL SaveDateTimeNumber(const struct tm *DateTime, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveDateTimeNumber(const struct tm *DateTime, LPLCMSICCPROFILE Icc) { icDateTimeNumber Dest; @@ -3003,14 +3056,14 @@ BOOL SaveDateTimeNumber(const struct tm *DateTime, LPLCMSICCPROFILE Icc) // Saves a named color list into a named color profile static -BOOL SaveNamedColorList(LPcmsNAMEDCOLORLIST NamedColorList, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveNamedColorList(LPcmsNAMEDCOLORLIST NamedColorList, LPLCMSICCPROFILE Icc) { icUInt32Number vendorFlag; // Bottom 16 bits for IC use icUInt32Number count; // Count of named colors icUInt32Number nDeviceCoords; // Num of device coordinates - icInt8Number prefix[32]; // Prefix for each color name - icInt8Number suffix[32]; // Suffix for each color name + char prefix[32]; // Prefix for each color name + char suffix[32]; // Suffix for each color name int i; if (!SetupBase(icSigNamedColor2Type, Icc)) return FALSE; @@ -3019,8 +3072,10 @@ BOOL SaveNamedColorList(LPcmsNAMEDCOLORLIST NamedColorList, LPLCMSICCPROFILE Icc count = TransportValue32(NamedColorList ->nColors); nDeviceCoords = TransportValue32(NamedColorList ->ColorantCount); - strncpy(prefix, (const char*) NamedColorList->Prefix, 32); - strncpy(suffix, (const char*) NamedColorList->Suffix, 32); + strncpy(prefix, (const char*) NamedColorList->Prefix, 31); + strncpy(suffix, (const char*) NamedColorList->Suffix, 31); + + suffix[31] = prefix[31] = 0; if (!Icc ->Write(Icc, sizeof(icUInt32Number), &vendorFlag)) return FALSE; if (!Icc ->Write(Icc, sizeof(icUInt32Number), &count)) return FALSE; @@ -3030,15 +3085,17 @@ BOOL SaveNamedColorList(LPcmsNAMEDCOLORLIST NamedColorList, LPLCMSICCPROFILE Icc for (i=0; i < NamedColorList ->nColors; i++) { - icUInt16Number PCS[3]; - icUInt16Number Colorant[MAXCHANNELS]; - icInt8Number root[32]; + icUInt16Number PCS[3]; + icUInt16Number Colorant[MAXCHANNELS]; + char root[32]; LPcmsNAMEDCOLOR Color; int j; Color = NamedColorList ->List + i; - strncpy((char*) root, Color ->Name, 32); + strncpy(root, Color ->Name, 32); + Color ->Name[32] = 0; + if (!Icc ->Write(Icc, 32 , root)) return FALSE; for (j=0; j < 3; j++) @@ -3062,7 +3119,7 @@ BOOL SaveNamedColorList(LPcmsNAMEDCOLORLIST NamedColorList, LPLCMSICCPROFILE Icc // Saves a colorant table. It is using the named color structure for simplicity sake static -BOOL SaveColorantTable(LPcmsNAMEDCOLORLIST NamedColorList, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveColorantTable(LPcmsNAMEDCOLORLIST NamedColorList, LPLCMSICCPROFILE Icc) { icUInt32Number count; // Count of named colors int i; @@ -3076,13 +3133,15 @@ BOOL SaveColorantTable(LPcmsNAMEDCOLORLIST NamedColorList, LPLCMSICCPROFILE Icc) for (i=0; i < NamedColorList ->nColors; i++) { icUInt16Number PCS[3]; - icInt8Number root[32]; + icInt8Number root[33]; LPcmsNAMEDCOLOR Color; int j; Color = NamedColorList ->List + i; strncpy((char*) root, Color ->Name, 32); + root[32] = 0; + if (!Icc ->Write(Icc, 32 , root)) return FALSE; for (j=0; j < 3; j++) @@ -3099,7 +3158,7 @@ BOOL SaveColorantTable(LPcmsNAMEDCOLORLIST NamedColorList, LPLCMSICCPROFILE Icc) // Does serialization of LUT16 and writes it. static -BOOL SaveLUT(const LUT* NewLUT, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveLUT(const LUT* NewLUT, LPLCMSICCPROFILE Icc) { icLut16 LUT16; unsigned int i; @@ -3189,7 +3248,7 @@ BOOL SaveLUT(const LUT* NewLUT, LPLCMSICCPROFILE Icc) // Does serialization of LUT8 and writes it static -BOOL SaveLUT8(const LUT* NewLUT, LPLCMSICCPROFILE Icc) +LCMSBOOL SaveLUT8(const LUT* NewLUT, LPLCMSICCPROFILE Icc) { icLut8 LUT8; unsigned int i, j; @@ -3323,7 +3382,7 @@ void LCMSEXPORT _cmsSetLUTdepth(cmsHPROFILE hProfile, int depth) // Saves Tag directory static -BOOL SaveTagDirectory(LPLCMSICCPROFILE Icc) +LCMSBOOL SaveTagDirectory(LPLCMSICCPROFILE Icc) { icInt32Number i; icTag Tag; @@ -3356,7 +3415,7 @@ BOOL SaveTagDirectory(LPLCMSICCPROFILE Icc) // Dump tag contents static -BOOL SaveTags(LPLCMSICCPROFILE Icc) +LCMSBOOL SaveTags(LPLCMSICCPROFILE Icc, LPLCMSICCPROFILE FileOrig) { LPBYTE Data; @@ -3384,8 +3443,31 @@ BOOL SaveTags(LPLCMSICCPROFILE Icc) Icc -> TagOffsets[i] = Begin = Icc ->UsedSpace; Data = (LPBYTE) Icc -> TagPtrs[i]; - if (!Data) + if (!Data) { + + // Reach here if we are copying a tag from a disk-based ICC profile which has not been modified by user. + // In this case a blind copy of the block data is performed + + if (Icc -> TagOffsets[i]) { + + size_t TagSize = FileOrig -> TagSizes[i]; + size_t TagOffset = FileOrig -> TagOffsets[i]; + void* Mem; + + if (FileOrig ->Seek(FileOrig, TagOffset)) return FALSE; + + Mem = _cmsMalloc(TagSize); + + if (FileOrig ->Read(Mem, TagSize, 1, FileOrig) != 1) return FALSE; + if (!Icc ->Write(Icc, TagSize, Mem)) return FALSE; + + Icc -> TagSizes[i] = (Icc ->UsedSpace - Begin); + free(Mem); + } + continue; + } + switch (Icc -> TagNames[i]) { @@ -3464,6 +3546,10 @@ BOOL SaveTags(LPLCMSICCPROFILE Icc) break; + case icSigChromaticAdaptationTag: + if (!SaveXYZArray(3, (LPcmsCIEXYZ) Data, Icc)) return FALSE; + break; + default: return FALSE; } @@ -3480,9 +3566,9 @@ BOOL SaveTags(LPLCMSICCPROFILE Icc) // Add tags to profile structure -BOOL LCMSEXPORT cmsAddTag(cmsHPROFILE hProfile, icTagSignature sig, const void* Tag) +LCMSBOOL LCMSEXPORT cmsAddTag(cmsHPROFILE hProfile, icTagSignature sig, const void* Tag) { - BOOL rc; + LCMSBOOL rc; switch (sig) { @@ -3543,6 +3629,11 @@ BOOL LCMSEXPORT cmsAddTag(cmsHPROFILE hProfile, icTagSignature sig, const void* rc = _cmsAddColorantTableTag(hProfile, sig, (LPcmsNAMEDCOLORLIST) Tag); break; + + case icSigChromaticAdaptationTag: + rc = _cmsAddChromaticAdaptationTag(hProfile, sig, (const cmsCIEXYZ*) Tag); + break; + default: cmsSignalError(LCMS_ERRC_ABORTED, "cmsAddTag: Tag '%x' is unsupported", sig); return FALSE; @@ -3568,11 +3659,11 @@ BOOL LCMSEXPORT cmsAddTag(cmsHPROFILE hProfile, icTagSignature sig, const void* // Low-level save to disk. It closes the profile on exit -BOOL LCMSEXPORT _cmsSaveProfile(cmsHPROFILE hProfile, const char* FileName) +LCMSBOOL LCMSEXPORT _cmsSaveProfile(cmsHPROFILE hProfile, const char* FileName) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; LCMSICCPROFILE Keep; - BOOL rc; + LCMSBOOL rc; CopyMemory(&Keep, Icc, sizeof(LCMSICCPROFILE)); _cmsSetSaveToDisk(Icc, NULL); @@ -3581,7 +3672,7 @@ BOOL LCMSEXPORT _cmsSaveProfile(cmsHPROFILE hProfile, const char* FileName) if (!SaveHeader(Icc)) return FALSE; if (!SaveTagDirectory(Icc)) return FALSE; - if (!SaveTags(Icc)) return FALSE; + if (!SaveTags(Icc, &Keep)) return FALSE; _cmsSetSaveToDisk(Icc, FileName); @@ -3591,7 +3682,7 @@ BOOL LCMSEXPORT _cmsSaveProfile(cmsHPROFILE hProfile, const char* FileName) if (!SaveHeader(Icc)) goto CleanUp; if (!SaveTagDirectory(Icc)) goto CleanUp; - if (!SaveTags(Icc)) goto CleanUp; + if (!SaveTags(Icc, &Keep)) goto CleanUp; rc = (Icc ->Close(Icc) == 0); CopyMemory(Icc, &Keep, sizeof(LCMSICCPROFILE)); @@ -3608,7 +3699,7 @@ BOOL LCMSEXPORT _cmsSaveProfile(cmsHPROFILE hProfile, const char* FileName) // Low-level save from open stream -BOOL LCMSEXPORT _cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, +LCMSBOOL LCMSEXPORT _cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, size_t* BytesNeeded) { LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; @@ -3623,20 +3714,20 @@ BOOL LCMSEXPORT _cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, if (!SaveHeader(Icc)) return FALSE; if (!SaveTagDirectory(Icc)) return FALSE; - if (!SaveTags(Icc)) return FALSE; + if (!SaveTags(Icc, &Keep)) return FALSE; if (!MemPtr) { // update BytesSaved so caller knows how many bytes are needed for MemPtr *BytesNeeded = Icc ->UsedSpace; - CopyMemory(Icc, &Keep, sizeof(LCMSICCPROFILE)); + CopyMemory(Icc, &Keep, sizeof(LCMSICCPROFILE)); return TRUE; } if (*BytesNeeded < Icc ->UsedSpace) { // need at least UsedSpace in MemPtr to continue - CopyMemory(Icc, &Keep, sizeof(LCMSICCPROFILE)); + CopyMemory(Icc, &Keep, sizeof(LCMSICCPROFILE)); return FALSE; } @@ -3646,7 +3737,7 @@ BOOL LCMSEXPORT _cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, // Pass #2 does save to file into supplied stream if (!SaveHeader(Icc)) goto CleanUp; if (!SaveTagDirectory(Icc)) goto CleanUp; - if (!SaveTags(Icc)) goto CleanUp; + if (!SaveTags(Icc, &Keep)) goto CleanUp; // update BytesSaved so caller knows how many bytes put into stream *BytesNeeded = Icc ->UsedSpace; @@ -3661,3 +3752,4 @@ CleanUp: CopyMemory(Icc, &Keep, sizeof(LCMSICCPROFILE)); return FALSE; } + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c index 43032109121..1a222febf86 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -118,7 +118,7 @@ LPLUT LCMSEXPORT cmsAllocLUT(void) { LPLUT NewLUT; - NewLUT = (LPLUT) malloc(sizeof(LUT)); + NewLUT = (LPLUT) _cmsMalloc(sizeof(LUT)); if (NewLUT) ZeroMemory(NewLUT, sizeof(LUT)); @@ -171,9 +171,10 @@ void LCMSEXPORT cmsFreeLUT(LPLUT Lut) static LPVOID DupBlockTab(LPVOID Org, size_t size) { - LPVOID mem = malloc(size); + LPVOID mem = _cmsMalloc(size); + if (mem != NULL) + CopyMemory(mem, Org, size); - CopyMemory(mem, Org, size); return mem; } @@ -211,6 +212,37 @@ unsigned int UIpow(unsigned int a, unsigned int b) } +LCMSBOOL _cmsValidateLUT(LPLUT NewLUT) +{ + unsigned int calc = 1; + unsigned int oldCalc; + unsigned int power = NewLUT -> InputChan; + + if (NewLUT -> cLutPoints > 100) return FALSE; + if (NewLUT -> InputChan > MAXCHANNELS) return FALSE; + if (NewLUT -> OutputChan > MAXCHANNELS) return FALSE; + + if (NewLUT -> cLutPoints == 0) return TRUE; + + for (; power > 0; power--) { + + oldCalc = calc; + calc *= NewLUT -> cLutPoints; + + if (calc / NewLUT -> cLutPoints != oldCalc) { + return FALSE; + } + } + + oldCalc = calc; + calc *= NewLUT -> OutputChan; + if (NewLUT -> OutputChan && calc / NewLUT -> OutputChan != oldCalc) { + return FALSE; + } + + return TRUE; +} + LPLUT LCMSEXPORT cmsAlloc3DGrid(LPLUT NewLUT, int clutPoints, int inputChan, int outputChan) { DWORD nTabSize; @@ -220,12 +252,17 @@ LPLUT LCMSEXPORT cmsAlloc3DGrid(LPLUT NewLUT, int clutPoints, int inputChan, int NewLUT -> InputChan = inputChan; NewLUT -> OutputChan = outputChan; + if (!_cmsValidateLUT(NewLUT)) { + return NULL; + } - nTabSize = (NewLUT -> OutputChan * UIpow(NewLUT->cLutPoints, - NewLUT->InputChan) - * sizeof(WORD)); + nTabSize = NewLUT -> OutputChan * UIpow(NewLUT->cLutPoints, + NewLUT->InputChan); + + NewLUT -> T = (LPWORD) _cmsCalloc(sizeof(WORD), nTabSize); + nTabSize *= sizeof(WORD); + if (NewLUT -> T == NULL) return NULL; - NewLUT -> T = (LPWORD) malloc(nTabSize); ZeroMemory(NewLUT -> T, nTabSize); NewLUT ->Tsize = nTabSize; @@ -254,10 +291,12 @@ LPLUT LCMSEXPORT cmsAllocLinearTable(LPLUT NewLUT, LPGAMMATABLE Tables[], int nT for (i=0; i < NewLUT -> InputChan; i++) { - PtrW = (LPWORD) malloc(sizeof(WORD) * NewLUT -> InputEntries); + PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * NewLUT -> InputEntries); + if (PtrW == NULL) return NULL; + NewLUT -> L1[i] = PtrW; CopyMemory(PtrW, Tables[i]->GammaTable, sizeof(WORD) * NewLUT -> InputEntries); - CopyMemory(&NewLUT -> LCurvesSeed[0][i], &Tables[i] -> Seed, sizeof(LCMSGAMMAPARAMS)); + CopyMemory(&NewLUT -> LCurvesSeed[0][i], &Tables[i] -> Seed, sizeof(LCMSGAMMAPARAMS)); } @@ -268,10 +307,12 @@ LPLUT LCMSEXPORT cmsAllocLinearTable(LPLUT NewLUT, LPGAMMATABLE Tables[], int nT NewLUT -> OutputEntries = Tables[0] -> nEntries; for (i=0; i < NewLUT -> OutputChan; i++) { - PtrW = (LPWORD) malloc(sizeof(WORD) * NewLUT -> OutputEntries); + PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * NewLUT -> OutputEntries); + if (PtrW == NULL) return NULL; + NewLUT -> L2[i] = PtrW; CopyMemory(PtrW, Tables[i]->GammaTable, sizeof(WORD) * NewLUT -> OutputEntries); - CopyMemory(&NewLUT -> LCurvesSeed[1][i], &Tables[i] -> Seed, sizeof(LCMSGAMMAPARAMS)); + CopyMemory(&NewLUT -> LCurvesSeed[1][i], &Tables[i] -> Seed, sizeof(LCMSGAMMAPARAMS)); } break; @@ -285,10 +326,12 @@ LPLUT LCMSEXPORT cmsAllocLinearTable(LPLUT NewLUT, LPGAMMATABLE Tables[], int nT for (i=0; i < NewLUT -> InputChan; i++) { - PtrW = (LPWORD) malloc(sizeof(WORD) * NewLUT -> L3Entries); + PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * NewLUT -> L3Entries); + if (PtrW == NULL) return NULL; + NewLUT -> L3[i] = PtrW; CopyMemory(PtrW, Tables[i]->GammaTable, sizeof(WORD) * NewLUT -> L3Entries); - CopyMemory(&NewLUT -> LCurvesSeed[2][i], &Tables[i] -> Seed, sizeof(LCMSGAMMAPARAMS)); + CopyMemory(&NewLUT -> LCurvesSeed[2][i], &Tables[i] -> Seed, sizeof(LCMSGAMMAPARAMS)); } break; @@ -298,10 +341,12 @@ LPLUT LCMSEXPORT cmsAllocLinearTable(LPLUT NewLUT, LPGAMMATABLE Tables[], int nT NewLUT -> L4Entries = Tables[0] -> nEntries; for (i=0; i < NewLUT -> OutputChan; i++) { - PtrW = (LPWORD) malloc(sizeof(WORD) * NewLUT -> L4Entries); + PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * NewLUT -> L4Entries); + if (PtrW == NULL) return NULL; + NewLUT -> L4[i] = PtrW; CopyMemory(PtrW, Tables[i]->GammaTable, sizeof(WORD) * NewLUT -> L4Entries); - CopyMemory(&NewLUT -> LCurvesSeed[3][i], &Tables[i] -> Seed, sizeof(LCMSGAMMAPARAMS)); + CopyMemory(&NewLUT -> LCurvesSeed[3][i], &Tables[i] -> Seed, sizeof(LCMSGAMMAPARAMS)); } break; @@ -580,7 +625,7 @@ LPLUT _cmsBlessLUT8(LPLUT Lut) LPL16PARAMS p = &Lut ->CLut16params; - p8 = (LPL8PARAMS) malloc(sizeof(L8PARAMS)); + p8 = (LPL8PARAMS) _cmsMalloc(sizeof(L8PARAMS)); if (p8 == NULL) return NULL; // values comes * 257, so we can safely take first byte (x << 8 + x) @@ -593,8 +638,8 @@ LPLUT _cmsBlessLUT8(LPLUT Lut) if (Lut ->wFlags & LUT_HASTL1) { for (j=0; j < 3; j++) - StageABC[i] = cmsLinearInterpLUT16(StageABC[i], - Lut -> L1[i], + StageABC[j] = cmsLinearInterpLUT16(StageABC[j], + Lut -> L1[j], &Lut -> In16params); Lut ->wFlags &= ~LUT_HASTL1; } @@ -697,7 +742,7 @@ void EvalLUTdoubleKLab(LPLUT Lut, const VEC3* In, WORD FixedK, LPcmsCIELab Out) wIn[3] = FixedK; cmsEvalLUT(Lut, wIn, wOut); - cmsLabEncoded2Float(Out, wOut); + cmsLabEncoded2Float(Out, wOut); } // Builds a Jacobian CMY->Lab @@ -722,9 +767,9 @@ void ComputeJacobianLab(LPLUT Lut, LPMAT3 Jacobian, const VEC3* Colorant, WORD K EvalLUTdoubleKLab(Lut, &ColorantD, K, &LabD); - Jacobian->v[0].n[j] = ((LabD.L - Lab.L) / JACOBIAN_EPSILON); - Jacobian->v[1].n[j] = ((LabD.a - Lab.a) / JACOBIAN_EPSILON); - Jacobian->v[2].n[j] = ((LabD.b - Lab.b) / JACOBIAN_EPSILON); + Jacobian->v[0].n[j] = ((LabD.L - Lab.L) / JACOBIAN_EPSILON); + Jacobian->v[1].n[j] = ((LabD.a - Lab.a) / JACOBIAN_EPSILON); + Jacobian->v[2].n[j] = ((LabD.b - Lab.b) / JACOBIAN_EPSILON); } } @@ -797,18 +842,18 @@ LCMSAPI double LCMSEXPORT cmsEvalLUTreverse(LPLUT Lut, WORD Target[], WORD Resul // Obtain slope ComputeJacobianLab(Lut, &Jacobian, &x, FixedK); - // Solve system - tmp2.n[0] = fx.L - Goal.L; - tmp2.n[1] = fx.a - Goal.a; - tmp2.n[2] = fx.b - Goal.b; + // Solve system + tmp2.n[0] = fx.L - Goal.L; + tmp2.n[1] = fx.a - Goal.a; + tmp2.n[2] = fx.b - Goal.b; - if (!MAT3solve(&tmp, &Jacobian, &tmp2)) - break; + if (!MAT3solve(&tmp, &Jacobian, &tmp2)) + break; // Move our guess - x.n[0] -= tmp.n[0]; - x.n[1] -= tmp.n[1]; - x.n[2] -= tmp.n[2]; + x.n[0] -= tmp.n[0]; + x.n[1] -= tmp.n[1]; + x.n[2] -= tmp.n[2]; // Some clipping.... VEC3saturate(&x); @@ -822,3 +867,6 @@ LCMSAPI double LCMSEXPORT cmsEvalLUTreverse(LPLUT Lut, WORD Target[], WORD Resul return LastError; } + + + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmatsh.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmatsh.c index c70829989b2..9a6576bce23 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmatsh.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmatsh.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -62,6 +62,7 @@ // data yet in fixed point, so no additional process is required. // Then, we obtain data on 15.16, so we need to shift >> by 1 to // obtain 1.15 PCS format. + // On OUTPUT profiles, things are inverse, we must first expand 1 bit // by shifting left, and then convert result between 0 and 1.000 to // RGB, so FromFixedDomain() must be called before pass values to @@ -71,6 +72,7 @@ // input is encoded from 0 to 0xffff, we must first use the shaper and // then the matrix, an additional FromFixedDomain() must be used to // accomodate output values. + // For a sake of simplicity, I will handle this three behaviours // with different routines, so the flags MATSHAPER_INPUT and MATSHAPER_OUTPUT // can be conbined to signal smelted matrix-shapers @@ -89,7 +91,7 @@ int ComputeTables(LPGAMMATABLE Table[3], LPWORD Out[3], LPL16PARAMS p16) { LPWORD PtrW; - PtrW = (LPWORD) malloc(sizeof(WORD) * p16 -> nSamples); + PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * p16 -> nSamples); if (PtrW == NULL) return -1; // Signal error @@ -119,7 +121,7 @@ LPMATSHAPER cmsAllocMatShaper2(LPMAT3 Matrix, LPGAMMATABLE In[], LPGAMMATABLE Ou LPMATSHAPER NewMatShaper; int rc; - NewMatShaper = (LPMATSHAPER) malloc(sizeof(MATSHAPER)); + NewMatShaper = (LPMATSHAPER) _cmsMalloc(sizeof(MATSHAPER)); if (NewMatShaper) ZeroMemory(NewMatShaper, sizeof(MATSHAPER)); @@ -171,7 +173,13 @@ LPMATSHAPER cmsAllocMatShaper(LPMAT3 Matrix, LPGAMMATABLE Tables[], DWORD Behavi LPMATSHAPER NewMatShaper; int i, AllLinear; - NewMatShaper = (LPMATSHAPER) malloc(sizeof(MATSHAPER)); + if (Matrix == NULL) return NULL; + for (i=0; i < 3; i++) { + + if (Tables[i] == NULL) return NULL; + } + + NewMatShaper = (LPMATSHAPER) _cmsMalloc(sizeof(MATSHAPER)); if (NewMatShaper) ZeroMemory(NewMatShaper, sizeof(MATSHAPER)); @@ -187,17 +195,16 @@ LPMATSHAPER cmsAllocMatShaper(LPMAT3 Matrix, LPGAMMATABLE Tables[], DWORD Behavi NewMatShaper -> dwFlags |= MATSHAPER_HASMATRIX; // Now, on the table characteristics - cmsCalcL16Params(Tables[0] -> nEntries, &NewMatShaper -> p16); // Copy tables AllLinear = 0; - for (i=0; i < 3; i++) - { + for (i=0; i < 3; i++) { + LPWORD PtrW; - PtrW = (LPWORD) malloc(sizeof(WORD) * NewMatShaper -> p16.nSamples); + PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * NewMatShaper -> p16.nSamples); if (PtrW == NULL) { cmsFreeMatShaper(NewMatShaper); @@ -235,11 +242,11 @@ void cmsFreeMatShaper(LPMATSHAPER MatShaper) for (i=0; i < 3; i++) { - if (MatShaper -> L[i]) free(MatShaper ->L[i]); - if (MatShaper -> L2[i]) free(MatShaper ->L2[i]); + if (MatShaper -> L[i]) _cmsFree(MatShaper ->L[i]); + if (MatShaper -> L2[i]) _cmsFree(MatShaper ->L2[i]); } - free(MatShaper); + _cmsFree(MatShaper); } diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c index b404fdc6924..f6bc3cb5a59 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -71,16 +71,16 @@ double cdecl VEC3length(LPVEC3 a); double cdecl VEC3distance(LPVEC3 a, LPVEC3 b); -void cdecl MAT3identity(LPMAT3 a); -void cdecl MAT3per(LPMAT3 r, LPMAT3 a, LPMAT3 b); -int cdecl MAT3inverse(LPMAT3 a, LPMAT3 b); -BOOL cdecl MAT3solve(LPVEC3 x, LPMAT3 a, LPVEC3 b); -double cdecl MAT3det(LPMAT3 m); -void cdecl MAT3eval(LPVEC3 r, LPMAT3 a, LPVEC3 v); -void cdecl MAT3toFix(LPWMAT3 r, LPMAT3 v); -void cdecl MAT3evalW(LPWVEC3 r, LPWMAT3 a, LPWVEC3 v); -void cdecl MAT3perK(LPMAT3 r, LPMAT3 v, double d); -void cdecl MAT3scaleAndCut(LPWMAT3 r, LPMAT3 v, double d); +void cdecl MAT3identity(LPMAT3 a); +void cdecl MAT3per(LPMAT3 r, LPMAT3 a, LPMAT3 b); +int cdecl MAT3inverse(LPMAT3 a, LPMAT3 b); +LCMSBOOL cdecl MAT3solve(LPVEC3 x, LPMAT3 a, LPVEC3 b); +double cdecl MAT3det(LPMAT3 m); +void cdecl MAT3eval(LPVEC3 r, LPMAT3 a, LPVEC3 v); +void cdecl MAT3toFix(LPWMAT3 r, LPMAT3 v); +void cdecl MAT3evalW(LPWVEC3 r, LPWMAT3 a, LPWVEC3 v); +void cdecl MAT3perK(LPMAT3 r, LPMAT3 v, double d); +void cdecl MAT3scaleAndCut(LPWMAT3 r, LPMAT3 v, double d); // --------------------- Implementation ---------------------------- @@ -345,13 +345,13 @@ void VEC3minus(LPVEC3 r, LPVEC3 a, LPVEC3 b) // Check id two vectors are the same, allowing tolerance static -BOOL RangeCheck(double l, double h, double v) +LCMSBOOL RangeCheck(double l, double h, double v) { return (v >= l && v <= h); } -BOOL VEC3equal(LPWVEC3 a, LPWVEC3 b, double Tolerance) +LCMSBOOL VEC3equal(LPWVEC3 a, LPWVEC3 b, double Tolerance) { int i; double c; @@ -367,7 +367,7 @@ BOOL VEC3equal(LPWVEC3 a, LPWVEC3 b, double Tolerance) return TRUE; } -BOOL VEC3equalF(LPVEC3 a, LPVEC3 b, double Tolerance) +LCMSBOOL VEC3equalF(LPVEC3 a, LPVEC3 b, double Tolerance) { int i; double c; @@ -462,7 +462,7 @@ void MAT3identity(LPMAT3 a) // Check if matrix is Identity. Allow a tolerance as % -BOOL MAT3isIdentity(LPWMAT3 a, double Tolerance) +LCMSBOOL MAT3isIdentity(LPWMAT3 a, double Tolerance) { int i; MAT3 Idd; @@ -545,16 +545,16 @@ int MAT3inverse(LPMAT3 a, LPMAT3 b) // Solve a system in the form Ax = b -BOOL MAT3solve(LPVEC3 x, LPMAT3 a, LPVEC3 b) +LCMSBOOL MAT3solve(LPVEC3 x, LPMAT3 a, LPVEC3 b) { - MAT3 m, a_1; + MAT3 m, a_1; - CopyMemory(&m, a, sizeof(MAT3)); + CopyMemory(&m, a, sizeof(MAT3)); - if (!MAT3inverse(&m, &a_1)) return FALSE; // Singular matrix + if (!MAT3inverse(&m, &a_1)) return FALSE; // Singular matrix - MAT3eval(x, &a_1, b); - return TRUE; + MAT3eval(x, &a_1, b); + return TRUE; } @@ -839,3 +839,7 @@ void MAT3scaleAndCut(LPWMAT3 r, LPMAT3 v, double d) VEC3scaleAndCut(&r -> v[1], &v -> v[1], d); VEC3scaleAndCut(&r -> v[2], &v -> v[2], d); } + + + + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c index c943badcb3b..c47d002f7cf 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -74,7 +74,7 @@ LPcmsNAMEDCOLORLIST GrowNamedColorList(LPcmsNAMEDCOLORLIST v, int ByElements) NewElements *= 2; size = sizeof(cmsNAMEDCOLORLIST) + (sizeof(cmsNAMEDCOLOR) * NewElements); - TheNewList = (LPcmsNAMEDCOLORLIST) malloc(size); + TheNewList = (LPcmsNAMEDCOLORLIST) _cmsMalloc(size); if (TheNewList == NULL) { @@ -86,7 +86,7 @@ LPcmsNAMEDCOLORLIST GrowNamedColorList(LPcmsNAMEDCOLORLIST v, int ByElements) CopyMemory(TheNewList, v, sizeof(cmsNAMEDCOLORLIST) + (v ->nColors - 1) * sizeof(cmsNAMEDCOLOR)); TheNewList -> Allocated = NewElements; - free(v); + _cmsFree(v); return TheNewList; } } @@ -99,7 +99,7 @@ LPcmsNAMEDCOLORLIST cmsAllocNamedColorList(int n) { size_t size = sizeof(cmsNAMEDCOLORLIST) + (n - 1) * sizeof(cmsNAMEDCOLOR); - LPcmsNAMEDCOLORLIST v = (LPcmsNAMEDCOLORLIST) malloc(size); + LPcmsNAMEDCOLORLIST v = (LPcmsNAMEDCOLORLIST) _cmsMalloc(size); if (v == NULL) { @@ -124,10 +124,10 @@ void cmsFreeNamedColorList(LPcmsNAMEDCOLORLIST v) return; } - free(v); + _cmsFree(v); } -BOOL cmsAppendNamedColor(cmsHTRANSFORM xform, const char* Name, WORD PCS[3], WORD Colorant[MAXCHANNELS]) +LCMSBOOL cmsAppendNamedColor(cmsHTRANSFORM xform, const char* Name, WORD PCS[3], WORD Colorant[MAXCHANNELS]) { _LPcmsTRANSFORM v = (_LPcmsTRANSFORM) xform; LPcmsNAMEDCOLORLIST List; @@ -146,6 +146,7 @@ BOOL cmsAppendNamedColor(cmsHTRANSFORM xform, const char* Name, WORD PCS[3], WOR List ->List[List ->nColors].PCS[i] = PCS[i]; strncpy(List ->List[List ->nColors].Name, Name, MAX_PATH-1); + List ->List[List ->nColors].Name[MAX_PATH-1] = 0; List ->nColors++; return TRUE; @@ -164,18 +165,17 @@ int LCMSEXPORT cmsNamedColorCount(cmsHTRANSFORM xform) } -BOOL LCMSEXPORT cmsNamedColorInfo(cmsHTRANSFORM xform, int nColor, char* Name, char* Prefix, char* Suffix) +LCMSBOOL LCMSEXPORT cmsNamedColorInfo(cmsHTRANSFORM xform, int nColor, char* Name, char* Prefix, char* Suffix) { _LPcmsTRANSFORM v = (_LPcmsTRANSFORM) xform; - if (v ->NamedColorList == NULL) return FALSE; if (nColor < 0 || nColor >= cmsNamedColorCount(xform)) return FALSE; - if (Name) strncpy(Name, v ->NamedColorList->List[nColor].Name, 31); - if (Prefix) strncpy(Prefix, v ->NamedColorList->Prefix, 31); - if (Suffix) strncpy(Suffix, v ->NamedColorList->Suffix, 31); + if (Name) { strncpy(Name, v ->NamedColorList->List[nColor].Name, 31); Name[31] = 0; } + if (Prefix) { strncpy(Prefix, v ->NamedColorList->Prefix, 31); Prefix[31] = 0; } + if (Suffix) { strncpy(Suffix, v ->NamedColorList->Suffix, 31); Suffix[31] = 0; } return TRUE; } @@ -196,3 +196,5 @@ int LCMSEXPORT cmsNamedColorIndex(cmsHTRANSFORM xform, const char* Name) return -1; } + + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c index ca76c07844a..6c5ef725635 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c @@ -28,7 +28,7 @@ // file: // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -639,9 +639,81 @@ LPBYTE UnrollDouble(register _LPcmsTRANSFORM info, register WORD wIn[], register +static +LPBYTE UnrollDouble1Chan(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum) +{ + double* Inks = (double*) accum; + double v; + + + v = floor(Inks[0] * 65535.0 + 0.5); + + if (v > 65535.0) v = 65535.0; + if (v < 0) v = 0; + + + wIn[0] = wIn[1] = wIn[2] = (WORD) v; + + return accum + sizeof(double); +} + + // ----------------------------------------------------------- Packing routines +// Generic N-bytes plus dither 16-to-8 conversion. Currently is just a quick hack + +static int err[MAXCHANNELS]; + +static +LPBYTE PackNBytesDither(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output) +{ + int nChan = T_CHANNELS(info -> OutputFormat); + register int i; + unsigned int n, pe, pf; + + for (i=0; i < nChan; i++) { + + n = wOut[i] + err[i]; // Value + + pe = (n / 257); // Whole part + pf = (n % 257); // Fractional part + + err[i] = pf; // Store it for next pixel + + *output++ = (BYTE) pe; + } + + return output + T_EXTRA(info ->OutputFormat); +} + + + +static +LPBYTE PackNBytesSwapDither(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output) +{ + int nChan = T_CHANNELS(info -> OutputFormat); + register int i; + unsigned int n, pe, pf; + + for (i=nChan-1; i >= 0; --i) { + + n = wOut[i] + err[i]; // Value + + pe = (n / 257); // Whole part + pf = (n % 257); // Fractional part + + err[i] = pf; // Store it for next pixel + + *output++ = (BYTE) pe; + } + + + return output + T_EXTRA(info ->OutputFormat); +} + + + // Generic chunky for byte static @@ -1486,7 +1558,10 @@ _cmsFIXFN _cmsIdentifyInputFormat(_LPcmsTRANSFORM xform, DWORD dwInput) case PT_HSV: case PT_HLS: case PT_Yxy: - FromInput = UnrollDouble; + if (T_CHANNELS(dwInput) == 1) + FromInput = UnrollDouble1Chan; + else + FromInput = UnrollDouble; break; // Inks (%) 0.0 .. 100.0 @@ -1749,6 +1824,9 @@ _cmsFIXFN _cmsIdentifyOutputFormat(_LPcmsTRANSFORM xform, DWORD dwOutput) switch (T_CHANNELS(dwOutput)) { case 1: + if (T_DITHER(dwOutput)) + ToOutput = PackNBytesDither; + else ToOutput = Pack1Byte; if (T_EXTRA(dwOutput) == 1) { if (T_SWAPFIRST(dwOutput)) @@ -1766,8 +1844,12 @@ _cmsFIXFN _cmsIdentifyOutputFormat(_LPcmsTRANSFORM xform, DWORD dwOutput) else if (T_COLORSPACE(dwOutput) == PT_Lab) ToOutput = Pack3BytesLab; + else { + if (T_DITHER(dwOutput)) + ToOutput = PackNBytesDither; else ToOutput = Pack3Bytes; + } break; case 1: // TODO: ALab8 should be handled here @@ -1793,12 +1875,22 @@ _cmsFIXFN _cmsIdentifyOutputFormat(_LPcmsTRANSFORM xform, DWORD dwOutput) case 4: if (T_EXTRA(dwOutput) == 0) { + if (T_DOSWAP(dwOutput)) { - if (T_SWAPFIRST(dwOutput)) + + if (T_SWAPFIRST(dwOutput)) { ToOutput = Pack4BytesSwapSwapFirst; - else + } + else { + + if (T_DITHER(dwOutput)) { + ToOutput = PackNBytesSwapDither; + } + else { ToOutput = Pack4BytesSwap; + } + } } else { if (T_SWAPFIRST(dwOutput)) @@ -1807,11 +1899,15 @@ _cmsFIXFN _cmsIdentifyOutputFormat(_LPcmsTRANSFORM xform, DWORD dwOutput) if (T_FLAVOR(dwOutput)) ToOutput = Pack4BytesReverse; + else { + if (T_DITHER(dwOutput)) + ToOutput = PackNBytesDither; else ToOutput = Pack4Bytes; } } } + } else { if (!T_DOSWAP(dwOutput) && !T_SWAPFIRST(dwOutput)) ToOutput = PackNBytes; @@ -1833,7 +1929,7 @@ _cmsFIXFN _cmsIdentifyOutputFormat(_LPcmsTRANSFORM xform, DWORD dwOutput) } break; - case 2: + case 2: case 5: case 7: case 8: @@ -1849,8 +1945,13 @@ _cmsFIXFN _cmsIdentifyOutputFormat(_LPcmsTRANSFORM xform, DWORD dwOutput) { if (T_DOSWAP(dwOutput)) ToOutput = PackNBytesSwap; + else { + + if (T_DITHER(dwOutput)) + ToOutput = PackNBytesDither; else ToOutput = PackNBytes; + } } break; @@ -1984,7 +2085,7 @@ _cmsFIXFN _cmsIdentifyOutputFormat(_LPcmsTRANSFORM xform, DWORD dwOutput) break; - case 2: + case 2: case 5: case 7: case 8: diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c index 4ad975550c3..e9b3d2ed545 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -624,3 +624,7 @@ void LCMSEXPORT cmsXYZEncoded2Float(LPcmsCIEXYZ fXYZ, const WORD XYZ[3]) fXYZ -> Z = XYZ2float(XYZ[2]); } + + + + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c index f3bf7ec6fe8..22a67c0772d 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -144,6 +144,8 @@ LCMSAPI DWORD LCMSEXPORT cmsGetPostScriptCRDEx(cmsHPROFILE hProfile, int Intent, /Table [ p p p [<...>]] /RangeABC [ 0 1 0 1 0 1] /DecodeABC[ ] + /RangeLMN [ -0.236 1.254 0 1 -0.635 1.640 ] + % -128/500 1+127/500 0 1 -127/200 1+128/200 /MatrixABC [ 1 1 1 1 0 0 0 0 -1] /WhitePoint [D50] /BlackPoint [BP] @@ -347,7 +349,8 @@ typedef struct { static LPMEMSTREAM CreateMemStream(LPBYTE Buffer, DWORD dwMax, int MaxCols) { - LPMEMSTREAM m = (LPMEMSTREAM) malloc(sizeof(MEMSTREAM)); + LPMEMSTREAM m = (LPMEMSTREAM) _cmsMalloc(sizeof(MEMSTREAM)); + if (m == NULL) return NULL; ZeroMemory(m, sizeof(MEMSTREAM)); @@ -376,9 +379,9 @@ BYTE Word2Byte(WORD w) static BYTE L2Byte(WORD w) { - int ww = w + 0x0080; + int ww = w + 0x0080; - if (ww > 0xFFFF) return 0xFF; + if (ww > 0xFFFF) return 0xFF; return (BYTE) ((WORD) (ww >> 8) & 0xFF); } @@ -387,7 +390,6 @@ BYTE L2Byte(WORD w) static void WriteRawByte(LPMEMSTREAM m, BYTE b) { - if (m -> dwUsed + 1 > m -> dwMax) { m -> HasError = 1; } @@ -422,7 +424,7 @@ void WriteByte(LPMEMSTREAM m, BYTE b) } -// Does write a formatted string +// Does write a formatted string. Guaranteed to be 2048 bytes at most. static void Writef(LPMEMSTREAM m, const char *frm, ...) { @@ -432,7 +434,7 @@ void Writef(LPMEMSTREAM m, const char *frm, ...) va_start(args, frm); - vsprintf((char*) Buffer, frm, args); + vsnprintf((char*) Buffer, 2048, frm, args); for (pt = Buffer; *pt; pt++) { @@ -562,7 +564,7 @@ void EmitLab2XYZ(LPMEMSTREAM m) Writef(m, "{255 mul 128 sub 200 div } bind\n"); Writef(m, "]\n"); Writef(m, "/MatrixABC [ 1 1 1 1 0 0 0 0 -1]\n"); - Writef(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n"); + Writef(m, "/RangeLMN [ -0.236 1.254 0 1 -0.635 1.640 ]\n"); Writef(m, "/DecodeLMN [\n"); Writef(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.964200 mul} bind\n"); Writef(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse } bind\n"); @@ -584,7 +586,11 @@ void Emit1Gamma(LPMEMSTREAM m, LPWORD Table, int nEntries) if (nEntries <= 0) return; // Empty table // Suppress whole if identity - if (cmsIsLinear(Table, nEntries)) return; + if (cmsIsLinear(Table, nEntries)) { + Writef(m, "{} "); + return; + } + // Check if is really an exponential. If so, emit "exp" gamma = cmsEstimateGammaEx(Table, nEntries, 0.001); @@ -646,7 +652,7 @@ void Emit1Gamma(LPMEMSTREAM m, LPWORD Table, int nEntries) // Compare gamma table static -BOOL GammaTableEquals(LPWORD g1, LPWORD g2, int nEntries) +LCMSBOOL GammaTableEquals(LPWORD g1, LPWORD g2, int nEntries) { return memcmp(g1, g2, nEntries* sizeof(WORD)) == 0; } @@ -676,7 +682,7 @@ void EmitNGamma(LPMEMSTREAM m, int n, LPWORD g[], int nEntries) // Check whatever a profile has CLUT tables (only on input) static -BOOL IsLUTbased(cmsHPROFILE hProfile, int Intent) +LCMSBOOL IsLUTbased(cmsHPROFILE hProfile, int Intent) { icTagSignature Tag; @@ -718,10 +724,10 @@ int OutputValueSampler(register WORD In[], register WORD Out[], register LPVOID if (sc -> FixWhite) { - if (In[0] == 0xFFFF) { // Only in L* = 100 + if (In[0] == 0xFFFF) { // Only in L* = 100, ab = [-8..8] - if ((In[1] >= 0x8000 && In[1] <= 0x87FF) || - (In[2] >= 0x8000 && In[2] <= 0x87FF)) { + if ((In[1] >= 0x7800 && In[1] <= 0x8800) && + (In[2] >= 0x7800 && In[2] <= 0x8800)) { WORD* Black; WORD* White; @@ -829,8 +835,8 @@ void WriteCLUT(LPMEMSTREAM m, LPLUT Lut, int bps, const char* PreMaj, sc.PreMaj = PreMaj; sc.PostMaj= PostMaj; - sc.PreMin = PreMin; - sc.PostMin= PostMin; + sc.PreMin = PreMin; + sc.PostMin = PostMin; sc.lIsInput = lIsInput; sc.FixWhite = FixWhite; sc.ColorSpace = ColorSpace; @@ -1231,7 +1237,7 @@ DWORD LCMSEXPORT cmsGetPostScriptCSA(cmsHPROFILE hProfile, if (!WriteNamedColorCSA(mem, hProfile, Intent)) { - free((void*) mem); + _cmsFree((void*) mem); return 0; } } @@ -1246,7 +1252,7 @@ DWORD LCMSEXPORT cmsGetPostScriptCSA(cmsHPROFILE hProfile, ColorSpace != icSigLabData) { cmsSignalError(LCMS_ERRC_ABORTED, "Invalid output color space"); - free((void*) mem); + _cmsFree((void*) mem); return 0; } @@ -1256,7 +1262,7 @@ DWORD LCMSEXPORT cmsGetPostScriptCSA(cmsHPROFILE hProfile, // Yes, so handle as LUT-based if (!WriteInputLUT(mem, hProfile, Intent)) { - free((void*) mem); + _cmsFree((void*) mem); return 0; } } @@ -1266,7 +1272,7 @@ DWORD LCMSEXPORT cmsGetPostScriptCSA(cmsHPROFILE hProfile, if (!WriteInputMatrixShaper(mem, hProfile)) { - free((void*) mem); // Something went wrong + _cmsFree((void*) mem); // Something went wrong return 0; } } @@ -1277,7 +1283,7 @@ DWORD LCMSEXPORT cmsGetPostScriptCSA(cmsHPROFILE hProfile, dwBytesUsed = mem ->dwUsed; // Get rid of memory stream - free((void*) mem); + _cmsFree((void*) mem); // Finally, return used byte count return dwBytesUsed; @@ -1350,27 +1356,40 @@ DWORD LCMSEXPORT cmsGetPostScriptCSA(cmsHPROFILE hProfile, static -void EmitPQRStage(LPMEMSTREAM m, int DoBPC, int lIsAbsolute) +void EmitPQRStage(LPMEMSTREAM m, cmsHPROFILE hProfile, int DoBPC, int lIsAbsolute) { + if (lIsAbsolute) { + + // For absolute colorimetric intent, encode back to relative + // and generate a relative LUT + + // Relative encoding is obtained across XYZpcs*(D50/WhitePoint) + + cmsCIEXYZ White; + + cmsTakeMediaWhitePoint(&White, hProfile); + + Writef(m,"/MatrixPQR [1 0 0 0 1 0 0 0 1 ]\n"); + Writef(m,"/RangePQR [ -0.5 2 -0.5 2 -0.5 2 ]\n"); + + Writef(m, "%% Absolute colorimetric -- encode to relative to maximize LUT usage\n" + "/TransformPQR [\n" + "{0.9642 mul %g div exch pop exch pop exch pop exch pop} bind\n" + "{1.0000 mul %g div exch pop exch pop exch pop exch pop} bind\n" + "{0.8249 mul %g div exch pop exch pop exch pop exch pop} bind\n]\n", + White.X, White.Y, White.Z); + return; + } + + Writef(m,"%% Bradford Cone Space\n" "/MatrixPQR [0.8951 -0.7502 0.0389 0.2664 1.7135 -0.0685 -0.1614 0.0367 1.0296 ] \n"); Writef(m, "/RangePQR [ -0.5 2 -0.5 2 -0.5 2 ]\n"); - if (lIsAbsolute) { - - // For absolute colorimetric intent, do nothing - - Writef(m, "%% Absolute colorimetric -- no transformation\n" - "/TransformPQR [\n" - "{exch pop exch pop exch pop exch pop} bind dup dup]\n"); - return; - } - - // No BPC if (!DoBPC) { @@ -1414,6 +1433,7 @@ void EmitPQRStage(LPMEMSTREAM m, int DoBPC, int lIsAbsolute) static void EmitXYZ2Lab(LPMEMSTREAM m) { + Writef(m, "/RangeLMN [ -0.635 2.0 0 2 -0.635 2.0 ]\n"); Writef(m, "/EncodeLMN [\n"); Writef(m, "{ 0.964200 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n"); Writef(m, "{ 1.000000 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n"); @@ -1423,18 +1443,11 @@ void EmitXYZ2Lab(LPMEMSTREAM m) Writef(m, "/EncodeABC [\n"); - Writef(m, "{ 116 mul 16 sub 100 div } bind\n"); - Writef(m, "{ 500 mul 128 add 255 div } bind\n"); - Writef(m, "{ 200 mul 128 add 255 div } bind\n"); + Writef(m, "{ 500 mul 128 add 256 div } bind\n"); + Writef(m, "{ 200 mul 128 add 256 div } bind\n"); - /* - Writef(m, "{ 116 mul 16 sub 256 mul 25700 div } bind\n"); - Writef(m, "{ 500 mul 128 add 256 mul 65535 div } bind\n"); - Writef(m, "{ 200 mul 128 add 256 mul 65535 div } bind\n"); - */ - Writef(m, "]\n"); @@ -1458,20 +1471,27 @@ int WriteOutputLUT(LPMEMSTREAM m, cmsHPROFILE hProfile, int Intent, DWORD dwFlag LPLUT DeviceLink; cmsHPROFILE Profiles[3]; cmsCIEXYZ BlackPointAdaptedToD50; - BOOL lFreeDeviceLink = FALSE; - BOOL lDoBPC = (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION); + LCMSBOOL lFreeDeviceLink = FALSE; + LCMSBOOL lDoBPC = (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION); + LCMSBOOL lFixWhite = !(dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP); + int RelativeEncodingIntent; - // Trick our v4 profile as it were v2. This prevents the ajusting done - // in perceptual & saturation. We only neew v4 encoding! - hLab = cmsCreateLab4Profile(NULL); - cmsSetProfileICCversion(hLab, 0); + hLab = cmsCreateLabProfile(NULL); ColorSpace = cmsGetColorSpace(hProfile); nChannels = _cmsChannelsOf(ColorSpace); OutputFormat = CHANNELS_SH(nChannels) | BYTES_SH(2); + // For absolute colorimetric, the LUT is encoded as relative + // in order to preserve precission. + + RelativeEncodingIntent = Intent; + if (RelativeEncodingIntent == INTENT_ABSOLUTE_COLORIMETRIC) + RelativeEncodingIntent = INTENT_RELATIVE_COLORIMETRIC; + + // Is a devicelink profile? if (cmsGetDeviceClass(hProfile) == icSigLinkClass) { @@ -1479,13 +1499,14 @@ int WriteOutputLUT(LPMEMSTREAM m, cmsHPROFILE hProfile, int Intent, DWORD dwFlag if (ColorSpace == icSigLabData) { - // adjust input to Lab to out v4 + // adjust input to Lab to our v4 Profiles[0] = hLab; Profiles[1] = hProfile; xform = cmsCreateMultiprofileTransform(Profiles, 2, TYPE_Lab_DBL, - OutputFormat, Intent, cmsFLAGS_NOPRELINEARIZATION); + OutputFormat, RelativeEncodingIntent, + dwFlags|cmsFLAGS_NOWHITEONWHITEFIXUP|cmsFLAGS_NOPRELINEARIZATION); } else { @@ -1499,7 +1520,7 @@ int WriteOutputLUT(LPMEMSTREAM m, cmsHPROFILE hProfile, int Intent, DWORD dwFlag // This is a normal profile xform = cmsCreateTransform(hLab, TYPE_Lab_DBL, hProfile, - OutputFormat, Intent, cmsFLAGS_NOPRELINEARIZATION); + OutputFormat, RelativeEncodingIntent, dwFlags|cmsFLAGS_NOWHITEONWHITEFIXUP|cmsFLAGS_NOPRELINEARIZATION); } if (xform == NULL) { @@ -1515,7 +1536,7 @@ int WriteOutputLUT(LPMEMSTREAM m, cmsHPROFILE hProfile, int Intent, DWORD dwFlag if (!DeviceLink) { - DeviceLink = _cmsPrecalculateDeviceLink(xform, 0); + DeviceLink = _cmsPrecalculateDeviceLink(xform, cmsFLAGS_NOPRELINEARIZATION); lFreeDeviceLink = TRUE; } @@ -1527,7 +1548,7 @@ int WriteOutputLUT(LPMEMSTREAM m, cmsHPROFILE hProfile, int Intent, DWORD dwFlag // Emit headers, etc. EmitWhiteBlackD50(m, &BlackPointAdaptedToD50); - EmitPQRStage(m, lDoBPC, Intent == INTENT_ABSOLUTE_COLORIMETRIC); + EmitPQRStage(m, hProfile, lDoBPC, Intent == INTENT_ABSOLUTE_COLORIMETRIC); EmitXYZ2Lab(m); if (DeviceLink ->wFlags & LUT_HASTL1) { @@ -1544,10 +1565,13 @@ int WriteOutputLUT(LPMEMSTREAM m, cmsHPROFILE hProfile, int Intent, DWORD dwFlag // zero. This would sacrifice a bit of highlights, but failure to do so would cause // scum dot. Ouch. + if (Intent == INTENT_ABSOLUTE_COLORIMETRIC) + lFixWhite = FALSE; + Writef(m, "/RenderTable "); WriteCLUT(m, DeviceLink, 8, "<", ">\n", "", "", FALSE, - (Intent != INTENT_ABSOLUTE_COLORIMETRIC), ColorSpace); + lFixWhite, ColorSpace); Writef(m, " %d {} bind ", nChannels); @@ -1582,6 +1606,9 @@ void BuildColorantList(char *Colorant, int nColorant, WORD Out[]) int j; Colorant[0] = 0; + if (nColorant > MAXCHANNELS) + nColorant = MAXCHANNELS; + for (j=0; j < nColorant; j++) { sprintf(Buff, "%.3f", Out[j] / 65535.0); @@ -1677,7 +1704,7 @@ DWORD LCMSEXPORT cmsGetPostScriptCRDEx(cmsHPROFILE hProfile, if (!WriteNamedColorCRD(mem, hProfile, Intent, dwFlags)) { - free((void*) mem); + _cmsFree((void*) mem); return 0; } } @@ -1687,7 +1714,7 @@ DWORD LCMSEXPORT cmsGetPostScriptCRDEx(cmsHPROFILE hProfile, if (!WriteOutputLUT(mem, hProfile, Intent, dwFlags)) { - free((void*) mem); + _cmsFree((void*) mem); return 0; } } @@ -1702,7 +1729,7 @@ DWORD LCMSEXPORT cmsGetPostScriptCRDEx(cmsHPROFILE hProfile, dwBytesUsed = mem ->dwUsed; // Get rid of memory stream - free((void*) mem); + _cmsFree((void*) mem); // Finally, return used byte count return dwBytesUsed; diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c index 023a732dfeb..2b52b2daf88 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -120,7 +120,7 @@ int ComponentOf(int n, int clut, int nColorant) // This routine does a sweep on whole input space, and calls its callback // function on knots. returns TRUE if all ok, FALSE otherwise. -BOOL LCMSEXPORT cmsSample3DGrid(LPLUT Lut, _cmsSAMPLER Sampler, LPVOID Cargo, DWORD dwFlags) +LCMSBOOL LCMSEXPORT cmsSample3DGrid(LPLUT Lut, _cmsSAMPLER Sampler, LPVOID Cargo, DWORD dwFlags) { int i, t, nTotalPoints, Colorant, index; WORD In[MAXCHANNELS], Out[MAXCHANNELS]; @@ -145,12 +145,16 @@ BOOL LCMSEXPORT cmsSample3DGrid(LPLUT Lut, _cmsSAMPLER Sampler, LPVOID Cargo, DW &Lut -> In16params); } + for (t=0; t < (int) Lut -> OutputChan; t++) + Out[t] = Lut->T[index + t]; - // if (dwFlags & SAMPLER_INSPECT) { + if (dwFlags & SAMPLER_HASTL2) { for (t=0; t < (int) Lut -> OutputChan; t++) - Out[t] = Lut->T[index + t]; - // } + Out[t] = cmsLinearInterpLUT16(Out[t], + Lut -> L2[t], + &Lut -> Out16params); + } if (!Sampler(In, Out, Cargo)) @@ -255,9 +259,11 @@ LPLUT _cmsPrecalculateDeviceLink(cmsHTRANSFORM h, DWORD dwFlags) LPLUT Grid; int nGridPoints; DWORD dwFormatIn, dwFormatOut; + DWORD SaveFormatIn, SaveFormatOut; int ChannelsIn, ChannelsOut; LPLUT SaveGamutLUT; + // Remove any gamut checking SaveGamutLUT = p ->Gamut; p ->Gamut = NULL; @@ -276,8 +282,13 @@ LPLUT _cmsPrecalculateDeviceLink(cmsHTRANSFORM h, DWORD dwFlags) dwFormatIn = (CHANNELS_SH(ChannelsIn)|BYTES_SH(2)); dwFormatOut = (CHANNELS_SH(ChannelsOut)|BYTES_SH(2)); - p -> FromInput = _cmsIdentifyInputFormat(p, dwFormatIn); - p -> ToOutput = _cmsIdentifyOutputFormat(p, dwFormatOut); + SaveFormatIn = p ->InputFormat; + SaveFormatOut = p ->OutputFormat; + + p -> InputFormat = dwFormatIn; + p -> OutputFormat = dwFormatOut; + p -> FromInput = _cmsIdentifyInputFormat(p, dwFormatIn); + p -> ToOutput = _cmsIdentifyOutputFormat(p, dwFormatOut); // Fix gamut & gamma possible mismatches. @@ -289,7 +300,6 @@ LPLUT _cmsPrecalculateDeviceLink(cmsHTRANSFORM h, DWORD dwFlags) _cmsComputePrelinearizationTablesFromXFORM(hOne, 1, Grid); } - // Attention to this typecast! we can take the luxury to // do this since cmsHTRANSFORM is only an alias to a pointer // to the transform struct. @@ -297,11 +307,13 @@ LPLUT _cmsPrecalculateDeviceLink(cmsHTRANSFORM h, DWORD dwFlags) if (!cmsSample3DGrid(Grid, XFormSampler, (LPVOID) p, Grid -> wFlags)) { cmsFreeLUT(Grid); - return NULL; + Grid = NULL; } + p ->Gamut = SaveGamutLUT; + p ->InputFormat = SaveFormatIn; + p ->OutputFormat = SaveFormatOut; - p ->Gamut = SaveGamutLUT; return Grid; } @@ -348,7 +360,7 @@ int BlackPreservingGrayOnlySampler(register WORD In[], register WORD Out[], regi -// That is our K-preserving callback. +// Preserve all K plane. static int BlackPreservingSampler(register WORD In[], register WORD Out[], register LPVOID Cargo) { @@ -469,6 +481,7 @@ int LCMSEXPORT cmsSetCMYKPreservationStrategy(int n) return OldVal; } +#pragma warning(disable: 4550) // Get a pointer to callback on depending of strategy static @@ -504,11 +517,10 @@ LPLUT _cmsPrecalculateBlackPreservingDeviceLink(cmsHTRANSFORM hCMYK2CMYK, DWORD if (p -> dwOriginalFlags & cmsFLAGS_BLACKPOINTCOMPENSATION) LocalFlags |= cmsFLAGS_BLACKPOINTCOMPENSATION; - // Fill in cargo struct Cargo.cmyk2cmyk = hCMYK2CMYK; - // Compute tone curve + // Compute tone curve. Cargo.KTone = _cmsBuildKToneCurve(hCMYK2CMYK, 256); if (Cargo.KTone == NULL) return NULL; cmsCalcL16Params(Cargo.KTone ->nEntries, &Cargo.KToneParams); @@ -522,11 +534,11 @@ LPLUT _cmsPrecalculateBlackPreservingDeviceLink(cmsHTRANSFORM hCMYK2CMYK, DWORD Cargo.LabK2cmyk = cmsReadICCLut(p->OutputProfile, Device2PCS[p->Intent]); // Is there any table available? - if (Cargo.LabK2cmyk == NULL) { + if (Cargo.LabK2cmyk == NULL) { - Grid = NULL; + Grid = NULL; goto Cleanup; - } + } // Setup a roundtrip on output profile for TAC estimation Cargo.hRoundTrip = cmsCreateTransform(p ->OutputProfile, TYPE_CMYK_16, @@ -654,7 +666,7 @@ void PatchLUT(LPLUT Grid, WORD At[], WORD Value[], -BOOL _cmsFixWhiteMisalignment(_LPcmsTRANSFORM p) +LCMSBOOL _cmsFixWhiteMisalignment(_LPcmsTRANSFORM p) { WORD *WhitePointIn, *WhitePointOut, *BlackPointIn, *BlackPointOut; @@ -682,3 +694,4 @@ BOOL _cmsFixWhiteMisalignment(_LPcmsTRANSFORM p) return TRUE; } + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c index cd128dab6a4..9c3afc451dd 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -320,7 +320,7 @@ cmsHPROFILE LCMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, DWORD d cmsHPROFILE hICC; _LPcmsTRANSFORM v = (_LPcmsTRANSFORM) hTransform; LPLUT Lut; - BOOL MustFreeLUT; + LCMSBOOL MustFreeLUT; LPcmsNAMEDCOLORLIST InputColorant = NULL; LPcmsNAMEDCOLORLIST OutputColorant = NULL; @@ -373,10 +373,8 @@ cmsHPROFILE LCMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, DWORD d if (cmsGetDeviceClass(hICC) == icSigOutputClass) { - cmsAddTag(hICC, icSigBToA0Tag, (LPVOID) Lut); } - else cmsAddTag(hICC, icSigAToB0Tag, (LPVOID) Lut); @@ -404,7 +402,7 @@ cmsHPROFILE LCMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, DWORD d OutputColorant = cmsReadColorantTable(v ->OutputProfile, icSigColorantTableTag); } - } + } if (InputColorant) cmsAddTag(hICC, icSigColorantTableTag, InputColorant); @@ -446,6 +444,7 @@ cmsHPROFILE LCMSEXPORT cmsCreateLinearizationDeviceLink(icColorSpaceSignature Co // Creates a LUT with prelinearization step only Lut = cmsAllocLUT(); + if (Lut == NULL) return NULL; // Set up channels Lut ->InputChan = Lut ->OutputChan = _cmsChannelsOf(ColorSpace); @@ -548,6 +547,10 @@ cmsHPROFILE LCMSEXPORT cmsCreateInkLimitingDeviceLink(icColorSpaceSignature Colo // Creates a LUT with 3D grid only Lut = cmsAllocLUT(); + if (Lut == NULL) { + cmsCloseProfile(hICC); + return NULL; + } cmsAlloc3DGrid(Lut, 17, _cmsChannelsOf(ColorSpace), @@ -584,8 +587,9 @@ static LPLUT Create3x3EmptyLUT(void) { LPLUT AToB0 = cmsAllocLUT(); - AToB0 -> InputChan = AToB0 -> OutputChan = 3; + if (AToB0 == NULL) return NULL; + AToB0 -> InputChan = AToB0 -> OutputChan = 3; return AToB0; } @@ -597,8 +601,8 @@ cmsHPROFILE LCMSEXPORT cmsCreateLabProfile(LPcmsCIExyY WhitePoint) cmsHPROFILE hProfile; LPLUT Lut; - hProfile = cmsCreateRGBProfile(WhitePoint == NULL ? cmsD50_xyY() : WhitePoint, NULL, NULL); + if (hProfile == NULL) return NULL; cmsSetDeviceClass(hProfile, icSigAbstractClass); cmsSetColorSpace(hProfile, icSigLabData); @@ -611,7 +615,10 @@ cmsHPROFILE LCMSEXPORT cmsCreateLabProfile(LPcmsCIExyY WhitePoint) // An empty LUTs is all we need Lut = Create3x3EmptyLUT(); - if (Lut == NULL) return NULL; + if (Lut == NULL) { + cmsCloseProfile(hProfile); + return NULL; + } cmsAddTag(hProfile, icSigAToB0Tag, (LPVOID) Lut); cmsAddTag(hProfile, icSigBToA0Tag, (LPVOID) Lut); @@ -628,8 +635,8 @@ cmsHPROFILE LCMSEXPORT cmsCreateLab4Profile(LPcmsCIExyY WhitePoint) cmsHPROFILE hProfile; LPLUT Lut; - hProfile = cmsCreateRGBProfile(WhitePoint == NULL ? cmsD50_xyY() : WhitePoint, NULL, NULL); + if (hProfile == NULL) return NULL; cmsSetProfileICCversion(hProfile, 0x4000000); @@ -644,7 +651,10 @@ cmsHPROFILE LCMSEXPORT cmsCreateLab4Profile(LPcmsCIExyY WhitePoint) // An empty LUTs is all we need Lut = Create3x3EmptyLUT(); - if (Lut == NULL) return NULL; + if (Lut == NULL) { + cmsCloseProfile(hProfile); + return NULL; + } Lut -> wFlags |= LUT_V4_INPUT_EMULATE_V2; cmsAddTag(hProfile, icSigAToB0Tag, (LPVOID) Lut); @@ -666,6 +676,7 @@ cmsHPROFILE LCMSEXPORT cmsCreateXYZProfile(void) LPLUT Lut; hProfile = cmsCreateRGBProfile(cmsD50_xyY(), NULL, NULL); + if (hProfile == NULL) return NULL; cmsSetDeviceClass(hProfile, icSigAbstractClass); cmsSetColorSpace(hProfile, icSigXYZData); @@ -677,15 +688,16 @@ cmsHPROFILE LCMSEXPORT cmsCreateXYZProfile(void) // An empty LUTs is all we need Lut = Create3x3EmptyLUT(); - if (Lut == NULL) return NULL; + if (Lut == NULL) { + cmsCloseProfile(hProfile); + return NULL; + } cmsAddTag(hProfile, icSigAToB0Tag, (LPVOID) Lut); cmsAddTag(hProfile, icSigBToA0Tag, (LPVOID) Lut); cmsAddTag(hProfile, icSigPreview0Tag, (LPVOID) Lut); cmsFreeLUT(Lut); - - return hProfile; } @@ -723,6 +735,7 @@ LPGAMMATABLE Build_sRGBGamma(void) return cmsBuildParametricGamma(1024, 4, Parameters); } +// Create the ICC virtual profile for sRGB space cmsHPROFILE LCMSEXPORT cmsCreate_sRGBProfile(void) { cmsCIExyY D65; @@ -739,6 +752,7 @@ cmsHPROFILE LCMSEXPORT cmsCreate_sRGBProfile(void) hsRGB = cmsCreateRGBProfile(&D65, &Rec709Primaries, Gamma22); cmsFreeGamma(Gamma22[0]); + if (hsRGB == NULL) return NULL; cmsAddTag(hsRGB, icSigDeviceMfgDescTag, (LPVOID) "(lcms internal)"); @@ -750,7 +764,6 @@ cmsHPROFILE LCMSEXPORT cmsCreate_sRGBProfile(void) - typedef struct { double Brightness; double Contrast; @@ -793,7 +806,6 @@ int bchswSampler(register WORD In[], register WORD Out[], register LPVOID Cargo) cmsFloat2LabEncoded(Out, &LabOut); - return TRUE; } @@ -839,7 +851,10 @@ cmsHPROFILE LCMSEXPORT cmsCreateBCHSWabstractProfile(int nLUTPoints, // Creates a LUT with 3D grid only Lut = cmsAllocLUT(); - + if (Lut == NULL) { + cmsCloseProfile(hICC); + return NULL; + } cmsAlloc3DGrid(Lut, nLUTPoints, 3, 3); @@ -890,7 +905,10 @@ cmsHPROFILE LCMSEXPORT cmsCreateNULLProfile(void) // An empty LUTs is all we need Lut = cmsAllocLUT(); - if (Lut == NULL) return NULL; + if (Lut == NULL) { + cmsCloseProfile(hProfile); + return NULL; + } Lut -> InputChan = 3; Lut -> OutputChan = 1; diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c index 3f3beb76665..b7e38844de1 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -51,10 +51,6 @@ #include "lcms.h" -// Uncomment this line if you want lcms to use the black point tag in profile, -// if commented, lcms will compute the black point by its own. -// It is safer to leve it commented out -// #define HONOR_BLACK_POINT_TAG // Conversions @@ -79,10 +75,9 @@ void LCMSEXPORT cmsxyY2XYZ(LPcmsCIEXYZ Dest, const cmsCIExyY* Source) } - // Obtains WhitePoint from Temperature -BOOL LCMSEXPORT cmsWhitePointFromTemp(int TempK, LPcmsCIExyY WhitePoint) +LCMSBOOL LCMSEXPORT cmsWhitePointFromTemp(int TempK, LPcmsCIExyY WhitePoint) { double x, y; double T, T2, T3; @@ -147,7 +142,7 @@ BOOL LCMSEXPORT cmsWhitePointFromTemp(int TempK, LPcmsCIExyY WhitePoint) // - Then, I apply these coeficients to the original matrix -BOOL LCMSEXPORT cmsBuildRGB2XYZtransferMatrix(LPMAT3 r, LPcmsCIExyY WhitePt, +LCMSBOOL LCMSEXPORT cmsBuildRGB2XYZtransferMatrix(LPMAT3 r, LPcmsCIExyY WhitePt, LPcmsCIExyYTRIPLE Primrs) { VEC3 WhitePoint, Coef; @@ -169,14 +164,12 @@ BOOL LCMSEXPORT cmsBuildRGB2XYZtransferMatrix(LPMAT3 r, LPcmsCIExyY WhitePt, // Build Primaries matrix - VEC3init(&Primaries.v[0], xr, xg, xb); VEC3init(&Primaries.v[1], yr, yg, yb); VEC3init(&Primaries.v[2], (1-xr-yr), (1-xg-yg), (1-xb-yb)); // Result = Primaries ^ (-1) inverse matrix - if (!MAT3inverse(&Primaries, &Result)) return FALSE; @@ -184,11 +177,9 @@ BOOL LCMSEXPORT cmsBuildRGB2XYZtransferMatrix(LPMAT3 r, LPcmsCIExyY WhitePt, VEC3init(&WhitePoint, xn/yn, 1.0, (1.0-xn-yn)/yn); // Across inverse primaries ... - MAT3eval(&Coef, &Result, &WhitePoint); // Give us the Coefs, then I build transformation matrix - VEC3init(&r -> v[0], Coef.n[VX]*xr, Coef.n[VY]*xg, Coef.n[VZ]*xb); VEC3init(&r -> v[1], Coef.n[VX]*yr, Coef.n[VY]*yg, Coef.n[VZ]*yb); VEC3init(&r -> v[2], Coef.n[VX]*(1.0-xr-yr), Coef.n[VY]*(1.0-xg-yg), Coef.n[VZ]*(1.0-xb-yb)); @@ -246,7 +237,7 @@ void ComputeChromaticAdaptation(LPMAT3 Conversion, // Returns the final chrmatic adaptation from illuminant FromIll to Illuminant ToIll // The cone matrix can be specified in ConeMatrix. If NULL, Bradford is assumed -BOOL cmsAdaptationMatrix(LPMAT3 r, LPMAT3 ConeMatrix, LPcmsCIEXYZ FromIll, LPcmsCIEXYZ ToIll) +LCMSBOOL cmsAdaptationMatrix(LPMAT3 r, LPMAT3 ConeMatrix, LPcmsCIEXYZ FromIll, LPcmsCIEXYZ ToIll) { MAT3 LamRigg = {{ // Bradford matrix {{ 0.8951, 0.2664, -0.1614 }}, @@ -265,7 +256,7 @@ BOOL cmsAdaptationMatrix(LPMAT3 r, LPMAT3 ConeMatrix, LPcmsCIEXYZ FromIll, LPcms // Same as anterior, but assuming D50 destination. White point is given in xyY -BOOL cmsAdaptMatrixToD50(LPMAT3 r, LPcmsCIExyY SourceWhitePt) +LCMSBOOL cmsAdaptMatrixToD50(LPMAT3 r, LPcmsCIExyY SourceWhitePt) { cmsCIEXYZ Dn; MAT3 Bradford; @@ -284,7 +275,7 @@ BOOL cmsAdaptMatrixToD50(LPMAT3 r, LPcmsCIExyY SourceWhitePt) // Same as anterior, but assuming D50 source. White point is given in xyY -BOOL cmsAdaptMatrixFromD50(LPMAT3 r, LPcmsCIExyY DestWhitePt) +LCMSBOOL cmsAdaptMatrixFromD50(LPMAT3 r, LPcmsCIExyY DestWhitePt) { cmsCIEXYZ Dn; MAT3 Bradford; @@ -304,7 +295,7 @@ BOOL cmsAdaptMatrixFromD50(LPMAT3 r, LPcmsCIExyY DestWhitePt) // Adapts a color to a given illuminant. Original color is expected to have // a SourceWhitePt white point. -BOOL LCMSEXPORT cmsAdaptToIlluminant(LPcmsCIEXYZ Result, +LCMSBOOL LCMSEXPORT cmsAdaptToIlluminant(LPcmsCIEXYZ Result, LPcmsCIEXYZ SourceWhitePt, LPcmsCIEXYZ Illuminant, LPcmsCIEXYZ Value) @@ -404,8 +395,6 @@ double Robertson(LPcmsCIExyY v) dj = ((vs - vj) - tj * (us - uj)) / sqrt(1 + tj*tj); - - if ((j!=0) && (di/dj < 0.0)) { Tc = 1000000.0 / (mi + (di / (di - dj)) * (mj - mi)); break; @@ -423,7 +412,7 @@ double Robertson(LPcmsCIExyY v) static -BOOL InRange(LPcmsCIExyY a, LPcmsCIExyY b, double tolerance) +LCMSBOOL InRange(LPcmsCIExyY a, LPcmsCIExyY b, double tolerance) { double dist_x, dist_y; @@ -458,6 +447,7 @@ int FromD40toD150(LPWHITEPOINTS pts) } +// To be removed in future versions void _cmsIdentifyWhitePoint(char *Buffer, LPcmsCIEXYZ WhitePt) { int i, n; @@ -518,7 +508,6 @@ int BlackPointAsDarkerColorant(cmsHPROFILE hInput, cmsCIEXYZ BlackXYZ, MediaWhite; // If the profile does not support input direction, assume Black point 0 - if (!cmsIsIntentSupported(hInput, Intent, LCMS_USED_AS_INPUT)) { BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; @@ -527,7 +516,6 @@ int BlackPointAsDarkerColorant(cmsHPROFILE hInput, // Try to get black by using black colorant - Space = cmsGetColorSpace(hInput); if (!_cmsEndPointsBySpace(Space, &White, &Black, &nChannels)) { @@ -576,7 +564,7 @@ int BlackPointAsDarkerColorant(cmsHPROFILE hInput, // Get a black point of output CMYK profile, discounting any ink-limiting embedded -// in the profile. Fou doing that, use perceptual intent in input direction: +// in the profile. For doing that, use perceptual intent in input direction: // Lab (0, 0, 0) -> [Perceptual] Profile -> CMYK -> [Rel. colorimetric] Profile -> Lab static @@ -651,6 +639,8 @@ int GetV4PerceptualBlack(LPcmsCIEXYZ BlackPoint, cmsHPROFILE hProfile, DWORD dwF D50BlackPoint.X = PERCEPTUAL_BLACK_X; D50BlackPoint.Y = PERCEPTUAL_BLACK_Y; D50BlackPoint.Z = PERCEPTUAL_BLACK_Z; + + // Obtain the absolute XYZ. Adapt perceptual black back from D50 to whatever media white cmsAdaptToIlluminant(BlackPoint, cmsD50_XYZ(), &MediaWhite, &D50BlackPoint); } @@ -662,26 +652,24 @@ int GetV4PerceptualBlack(LPcmsCIEXYZ BlackPoint, cmsHPROFILE hProfile, DWORD dwF // This function shouldn't exist at all -- there is such quantity of broken // profiles on black point tag, that we must somehow fix chromaticity to // avoid huge tint when doing Black point compensation. This function does -// just that. If BP is specified, then forces it to neutral and uses only L -// component. If does not exist, computes it by taking 400% of ink or RGB=0 This -// works well on relative intent and is undefined on perceptual & saturation. -// However, I will support all intents for tricking & trapping. - +// just that. There is a special flag for using black point tag, but turned +// off by default because it is bogus on most profiles. The detection algorithm +// involves to turn BP to neutral and to use only L component. int cmsDetectBlackPoint(LPcmsCIEXYZ BlackPoint, cmsHPROFILE hProfile, int Intent, DWORD dwFlags) { - // v4 + perceptual & saturation intents does have its own black point + // v4 + perceptual & saturation intents does have its own black point, and it is + // well specified enough to use it. if ((cmsGetProfileICCversion(hProfile) >= 0x4000000) && (Intent == INTENT_PERCEPTUAL || Intent == INTENT_SATURATION)) { // Matrix shaper share MRC & perceptual intents - if (_cmsIsMatrixShaper(hProfile)) return BlackPointAsDarkerColorant(hProfile, INTENT_RELATIVE_COLORIMETRIC, BlackPoint, cmsFLAGS_NOTPRECALC); - // Get fixed value + // CLUT based - Get perceptual black point (fixed value) return GetV4PerceptualBlack(BlackPoint, hProfile, dwFlags); } @@ -701,7 +689,6 @@ int cmsDetectBlackPoint(LPcmsCIEXYZ BlackPoint, cmsHPROFILE hProfile, int Intent cmsTakeMediaWhitePoint(&MediaWhite, hProfile); // Black point is absolute XYZ, so adapt to D50 to get PCS value - cmsAdaptToIlluminant(&UntrustedBlackPoint, &MediaWhite, cmsD50_XYZ(), &BlackXYZ); // Force a=b=0 to get rid of any chroma @@ -713,7 +700,6 @@ int cmsDetectBlackPoint(LPcmsCIEXYZ BlackPoint, cmsHPROFILE hProfile, int Intent cmsLab2XYZ(NULL, &TrustedBlackPoint, &Lab); // Return BP as D50 relative or absolute XYZ (depends on flags) - if (!(dwFlags & LCMS_BPFLAGS_D50_ADAPTED)) cmsAdaptToIlluminant(BlackPoint, cmsD50_XYZ(), &MediaWhite, &TrustedBlackPoint); else @@ -724,15 +710,15 @@ int cmsDetectBlackPoint(LPcmsCIEXYZ BlackPoint, cmsHPROFILE hProfile, int Intent #endif - // If output profile, discount ink-limiting + // That is about v2 profiles. + // If output profile, discount ink-limiting and that's all if (Intent == INTENT_RELATIVE_COLORIMETRIC && (cmsGetDeviceClass(hProfile) == icSigOutputClass) && (cmsGetColorSpace(hProfile) == icSigCmykData)) return BlackPointUsingPerceptualBlack(BlackPoint, hProfile, dwFlags); // Nope, compute BP using current intent. - return BlackPointAsDarkerColorant(hProfile, Intent, BlackPoint, dwFlags); } diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c index 8b82f26c5f2..ec37bebb1e3 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -52,7 +52,6 @@ #include "lcms.h" -// #define DEBUG 1 // Transformations stuff // ----------------------------------------------------------------------- @@ -85,7 +84,7 @@ void LCMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform, void LCMSEXPORT cmsGetAlarmCodes(int *r, int *g, int *b); void LCMSEXPORT cmsSetAlarmCodes(int r, int g, int b); -BOOL LCMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, +LCMSBOOL LCMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, int Intent, int UsedDirection); // ------------------------------------------------------------------------- @@ -343,7 +342,7 @@ void PrecalculatedXFORM(_LPcmsTRANSFORM p, p ->DeviceLink ->CLut16params.Interp3D(wIn, wOut, p ->DeviceLink -> T, &p ->DeviceLink -> CLut16params); - } + } else cmsEvalLUT(p -> DeviceLink, wIn, wOut); @@ -414,7 +413,7 @@ void CachedXFORM(_LPcmsTRANSFORM p, register LPBYTE output; WORD wIn[MAXCHANNELS], wOut[MAXCHANNELS]; register unsigned int i, n; - WORD CacheIn[MAXCHANNELS], CacheOut[MAXCHANNELS]; + WORD CacheIn[MAXCHANNELS], CacheOut[MAXCHANNELS]; accum = (LPBYTE) in; @@ -427,10 +426,10 @@ void CachedXFORM(_LPcmsTRANSFORM p, ZeroMemory(wOut, sizeof(WORD) * MAXCHANNELS); - LCMS_READ_LOCK(&p ->rwlock); - CopyMemory(CacheIn, p ->CacheIn, sizeof(WORD) * MAXCHANNELS); - CopyMemory(CacheOut, p ->CacheOut, sizeof(WORD) * MAXCHANNELS); - LCMS_UNLOCK(&p ->rwlock); + LCMS_READ_LOCK(&p ->rwlock); + CopyMemory(CacheIn, p ->CacheIn, sizeof(WORD) * MAXCHANNELS); + CopyMemory(CacheOut, p ->CacheOut, sizeof(WORD) * MAXCHANNELS); + LCMS_UNLOCK(&p ->rwlock); for (i=0; i < n; i++) { @@ -443,14 +442,14 @@ void CachedXFORM(_LPcmsTRANSFORM p, } else { - // Try to speedup things on plain devicelinks + // Try to speedup things on plain devicelinks - if (p ->DeviceLink ->wFlags == LUT_HAS3DGRID) { + if (p ->DeviceLink ->wFlags == LUT_HAS3DGRID) { p ->DeviceLink ->CLut16params.Interp3D(wIn, wOut, p ->DeviceLink -> T, &p ->DeviceLink -> CLut16params); - } + } else cmsEvalLUT(p -> DeviceLink, wIn, wOut); @@ -463,10 +462,10 @@ void CachedXFORM(_LPcmsTRANSFORM p, } - LCMS_WRITE_LOCK(&p ->rwlock); - CopyMemory(p->CacheIn, CacheIn, sizeof(WORD) * MAXCHANNELS); - CopyMemory(p->CacheOut, CacheOut, sizeof(WORD) * MAXCHANNELS); - LCMS_UNLOCK(&p ->rwlock); + LCMS_WRITE_LOCK(&p ->rwlock); + CopyMemory(p->CacheIn, CacheIn, sizeof(WORD) * MAXCHANNELS); + CopyMemory(p->CacheOut, CacheOut, sizeof(WORD) * MAXCHANNELS); + LCMS_UNLOCK(&p ->rwlock); } @@ -483,7 +482,7 @@ void CachedXFORMGamutCheck(_LPcmsTRANSFORM p, register LPBYTE output; WORD wIn[MAXCHANNELS], wOut[MAXCHANNELS]; register unsigned int i, n; - WORD CacheIn[MAXCHANNELS], CacheOut[MAXCHANNELS]; + WORD CacheIn[MAXCHANNELS], CacheOut[MAXCHANNELS]; accum = (LPBYTE) in; @@ -495,10 +494,10 @@ void CachedXFORMGamutCheck(_LPcmsTRANSFORM p, ZeroMemory(wIn, sizeof(WORD) * MAXCHANNELS); ZeroMemory(wOut, sizeof(WORD) * MAXCHANNELS); - LCMS_READ_LOCK(&p ->rwlock); - CopyMemory(CacheIn, p ->CacheIn, sizeof(WORD) * MAXCHANNELS); - CopyMemory(CacheOut, p ->CacheOut, sizeof(WORD) * MAXCHANNELS); - LCMS_UNLOCK(&p ->rwlock); + LCMS_READ_LOCK(&p ->rwlock); + CopyMemory(CacheIn, p ->CacheIn, sizeof(WORD) * MAXCHANNELS); + CopyMemory(CacheOut, p ->CacheOut, sizeof(WORD) * MAXCHANNELS); + LCMS_UNLOCK(&p ->rwlock); for (i=0; i < n; i++) { @@ -520,10 +519,10 @@ void CachedXFORMGamutCheck(_LPcmsTRANSFORM p, output = p -> ToOutput(p, wOut, output); } - LCMS_WRITE_LOCK(&p ->rwlock); - CopyMemory(p->CacheIn, CacheIn, sizeof(WORD) * MAXCHANNELS); - CopyMemory(p->CacheOut, CacheOut, sizeof(WORD) * MAXCHANNELS); - LCMS_UNLOCK(&p ->rwlock); + LCMS_WRITE_LOCK(&p ->rwlock); + CopyMemory(p->CacheIn, CacheIn, sizeof(WORD) * MAXCHANNELS); + CopyMemory(p->CacheOut, CacheOut, sizeof(WORD) * MAXCHANNELS); + LCMS_UNLOCK(&p ->rwlock); } @@ -635,6 +634,8 @@ LPMATSHAPER cmsBuildGrayInputMatrixShaper(cmsHPROFILE hProfile) MAT3 Scale; GrayTRC = cmsReadICCGamma(hProfile, icSigGrayTRCTag); // Y + if (GrayTRC == NULL) return NULL; + cmsTakeIluminant(&Illuminant, hProfile); if (cmsGetPCS(hProfile) == icSigLabData) { @@ -789,6 +790,10 @@ LPMATSHAPER cmsBuildOutputMatrixShaper(cmsHPROFILE OutputProfile) InverseShapes[1] = cmsReadICCGammaReversed(OutputProfile, icSigGreenTRCTag); InverseShapes[2] = cmsReadICCGammaReversed(OutputProfile, icSigBlueTRCTag); + if (InverseShapes[0] == NULL || + InverseShapes[1] == NULL || + InverseShapes[2] == NULL) return NULL; + OutMatSh = cmsAllocMatShaper(&DoubleInv, InverseShapes, MATSHAPER_OUTPUT); cmsFreeGammaTriple(InverseShapes); @@ -801,7 +806,7 @@ LPMATSHAPER cmsBuildOutputMatrixShaper(cmsHPROFILE OutputProfile) // This function builds a transform matrix chaining parameters static -BOOL cmsBuildSmeltMatShaper(_LPcmsTRANSFORM p) +LCMSBOOL cmsBuildSmeltMatShaper(_LPcmsTRANSFORM p) { MAT3 From, To, ToInv, Transfer; LPGAMMATABLE In[3], InverseOut[3]; @@ -814,7 +819,6 @@ BOOL cmsBuildSmeltMatShaper(_LPcmsTRANSFORM p) if (!cmsReadICCMatrixRGB2XYZ(&To, p -> OutputProfile)) return FALSE; - // invert dest if (MAT3inverse(&To, &ToInv) < 0) @@ -838,10 +842,14 @@ BOOL cmsBuildSmeltMatShaper(_LPcmsTRANSFORM p) InverseOut[1] = cmsReadICCGammaReversed(p -> OutputProfile, icSigGreenTRCTag); InverseOut[2] = cmsReadICCGammaReversed(p -> OutputProfile, icSigBlueTRCTag); + if (!InverseOut[0] || !InverseOut[1] || !InverseOut[2]) { + cmsFreeGammaTriple(In); + return FALSE; + } + p -> SmeltMatShaper = cmsAllocMatShaper2(&Transfer, In, InverseOut, MATSHAPER_ALLSMELTED); cmsFreeGammaTriple(In); - cmsFreeGammaTriple(InverseOut); return (p -> SmeltMatShaper != NULL); @@ -1029,7 +1037,7 @@ void TakeConversionRoutines(_LPcmsTRANSFORM p, int DoBPC) // Check colorspace static -BOOL IsProperColorSpace(cmsHPROFILE hProfile, DWORD dwFormat, BOOL lUsePCS) +LCMSBOOL IsProperColorSpace(cmsHPROFILE hProfile, DWORD dwFormat, LCMSBOOL lUsePCS) { int Space = T_COLORSPACE(dwFormat); @@ -1049,10 +1057,10 @@ _LPcmsTRANSFORM AllocEmptyTransform(void) { // Allocate needed memory - _LPcmsTRANSFORM p = (_LPcmsTRANSFORM) malloc(sizeof(_cmsTRANSFORM)); + _LPcmsTRANSFORM p = (_LPcmsTRANSFORM) _cmsMalloc(sizeof(_cmsTRANSFORM)); if (!p) { - cmsSignalError(LCMS_ERRC_ABORTED, "cmsCreateTransform: malloc() failed"); + cmsSignalError(LCMS_ERRC_ABORTED, "cmsCreateTransform: _cmsMalloc() failed"); return NULL; } @@ -1078,7 +1086,7 @@ _LPcmsTRANSFORM AllocEmptyTransform(void) p -> ExitColorSpace = (icColorSpaceSignature) 0; p -> AdaptationState = GlobalAdaptationState; - LCMS_CREATE_LOCK(&p->rwlock); + LCMS_CREATE_LOCK(&p->rwlock); return p; } @@ -1269,12 +1277,12 @@ _LPcmsTRANSFORM PickTransformRoutine(_LPcmsTRANSFORM p, else { // Can we optimize matrix-shaper only transform? - if (*FromTagPtr == 0 && - *ToTagPtr == 0 && - !p->PreviewProfile && - p -> Intent != INTENT_ABSOLUTE_COLORIMETRIC && + if ((*FromTagPtr == 0) && + (*ToTagPtr == 0) && + (!p->PreviewProfile) && + (p -> Intent != INTENT_ABSOLUTE_COLORIMETRIC) && (p -> EntryColorSpace == icSigRgbData) && - (p -> ExitColorSpace == icSigRgbData) && + (p -> ExitColorSpace == icSigRgbData) && !(p -> dwOriginalFlags & cmsFLAGS_BLACKPOINTCOMPENSATION)) { // Yes... try to smelt matrix-shapers @@ -1530,7 +1538,6 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile, TakeConversionRoutines(p, dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION); - if (!(p -> dwOriginalFlags & cmsFLAGS_NOTPRECALC)) { LPLUT DeviceLink; @@ -1553,7 +1560,8 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile, DeviceLink = _cmsPrecalculateDeviceLink((cmsHTRANSFORM) p, dwFlags); } - if (p -> dwOriginalFlags & cmsFLAGS_GAMUTCHECK) { + // Allow to specify cmsFLAGS_GAMUTCHECK, even if no proofing profile is given + if ((p ->PreviewProfile != NULL) && (p -> dwOriginalFlags & cmsFLAGS_GAMUTCHECK)) { GamutCheck = _cmsPrecalculateGamutCheck((cmsHTRANSFORM) p); } @@ -1561,7 +1569,6 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile, // If input colorspace is Rgb, Cmy, then use tetrahedral interpolation // for speed reasons (it only works well on spaces on Luma is diagonal, and // not if luma is in separate channel) - if (p ->EntryColorSpace == icSigRgbData || p ->EntryColorSpace == icSigCmyData) { @@ -1663,12 +1670,12 @@ void LCMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform) cmsFreeMatShaper(p -> SmeltMatShaper); if (p ->NamedColorList) cmsFreeNamedColorList(p ->NamedColorList); - if (p -> GamutCheck) - cmsFreeLUT(p -> GamutCheck); + if (p -> GamutCheck) + cmsFreeLUT(p -> GamutCheck); - LCMS_FREE_LOCK(&p->rwlock); + LCMS_FREE_LOCK(&p->rwlock); - free((void *) p); + _cmsFree((void *) p); } @@ -1704,7 +1711,7 @@ void LCMSEXPORT cmsGetAlarmCodes(int *r, int *g, int *b) // Returns TRUE if the profile is implemented as matrix-shaper -BOOL LCMSEXPORT _cmsIsMatrixShaper(cmsHPROFILE hProfile) +LCMSBOOL LCMSEXPORT _cmsIsMatrixShaper(cmsHPROFILE hProfile) { switch (cmsGetColorSpace(hProfile)) { @@ -1728,7 +1735,7 @@ BOOL LCMSEXPORT _cmsIsMatrixShaper(cmsHPROFILE hProfile) } -BOOL LCMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, +LCMSBOOL LCMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, int Intent, int UsedDirection) { @@ -1774,6 +1781,16 @@ int MultiprofileSampler(register WORD In[], register WORD Out[], register LPVOID } +static +int IsAllowedInSingleXform(icProfileClassSignature aClass) +{ + return (aClass == icSigInputClass) || + (aClass == icSigDisplayClass) || + (aClass == icSigOutputClass) || + (aClass == icSigColorSpaceClass); +} + + // A multiprofile transform does chain several profiles into a single // devicelink. It couls also be used to merge named color profiles into // a single database. @@ -1805,10 +1822,16 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateMultiprofileTransform(cmsHPROFILE hProfiles[], // There is a simple case with just two profiles, try to catch it in order of getting // black preservation to work on this function, at least with two profiles. + if (nProfiles == 2) { - if ((cmsGetDeviceClass(hProfiles[0]) != icSigLinkClass) && - (cmsGetDeviceClass(hProfiles[1]) != icSigLinkClass)) + icProfileClassSignature Class1 = cmsGetDeviceClass(hProfiles[0]); + icProfileClassSignature Class2 = cmsGetDeviceClass(hProfiles[1]); + + // Only input, output and display are allowed + + if (IsAllowedInSingleXform(Class1) && + IsAllowedInSingleXform(Class2)) return cmsCreateTransform(hProfiles[0], dwInput, hProfiles[1], dwOutput, Intent, dwFlags); } @@ -1984,6 +2007,14 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateMultiprofileTransform(cmsHPROFILE hProfiles[], if (hLab) cmsCloseProfile(hLab); if (hXYZ) cmsCloseProfile(hXYZ); + + if (p ->EntryColorSpace == icSigRgbData || + p ->EntryColorSpace == icSigCmyData) { + + p->DeviceLink -> CLut16params.Interp3D = cmsTetrahedralInterp16; + } + + if ((Intent != INTENT_ABSOLUTE_COLORIMETRIC) && !(dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP)) _cmsFixWhiteMisalignment(p); diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/icc34.h b/jdk/src/share/native/sun/java2d/cmm/lcms/icc34.h index 409928362ac..6ae05188889 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/icc34.h +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/icc34.h @@ -206,6 +206,11 @@ typedef __int32_t icInt64Number[2]; #if defined(__sun) || defined(__hpux) || defined (__MINGW) || defined(__MINGW32__) +#if defined (__MINGW) || defined(__MINGW32__) +#include +#endif + + typedef uint8_t icUInt8Number; typedef uint16_t icUInt16Number; typedef uint32_t icUInt32Number; diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms.h b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms.h index 404c1020bb0..33b3cca67fd 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms.h +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms.h @@ -29,7 +29,7 @@ // // // Little cms -// Copyright (C) 1998-2006 Marti Maria +// Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -49,8 +49,8 @@ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// Version 1.16 -#undef DEBUG +// Version 1.18 + #ifndef __cms_H // ********** Configuration toggles **************************************** @@ -62,13 +62,8 @@ // virtually any machine. //#define USE_FLOAT 1 -#ifdef _WIN64 -#define USE_C 1 -#undef USE_ASSEMBLER -#else -#undef USE_C +// #define USE_C 1 #define USE_ASSEMBLER 1 -#endif // Define this if you are using this package as a DLL (windows only) @@ -77,15 +72,11 @@ // Uncomment if you are trying the engine in a non-windows environment // like linux, SGI, VAX, FreeBSD, BeOS, etc. -#if !defined(_WIN32) || !defined(_WIN64) #define NON_WINDOWS 1 -#endif // Uncomment this one if you are using big endian machines (only meaningful // when NON_WINDOWS is used) -#ifndef _LITTLE_ENDIAN -#define USE_BIG_ENDIAN 1 -#endif +// #define USE_BIG_ENDIAN 1 // Uncomment this one if your compiler/machine does support the // "long long" type This will speedup fixed point math. (USE_C only) @@ -104,18 +95,24 @@ // Uncomment this line on multithreading environments // #define USE_PTHREADS 1 +// Uncomment this line if you want lcms to use the black point tag in profile, +// if commented, lcms will compute the black point by its own. +// It is safer to leve it commented out +// #define HONOR_BLACK_POINT_TAG 1 + // ********** End of configuration toggles ****************************** -#define LCMS_VERSION 116 +#define LCMS_VERSION 118 // Microsoft VisualC++ // Deal with Microsoft's attempt at deprecating C standard runtime functions - #ifdef _MSC_VER # undef NON_WINDOWS # if (_MSC_VER >= 1400) +# ifndef _CRT_SECURE_NO_DEPRECATE # define _CRT_SECURE_NO_DEPRECATE 1 +# endif # endif #endif @@ -125,7 +122,6 @@ # undef NON_WINDOWS #endif - #include #include #include @@ -134,11 +130,11 @@ #include // Metroworks CodeWarrior - #ifdef __MWERKS__ # define unlink remove # if WIN32 # define USE_CUSTOM_SWAB 1 +# undef NON_WINDOWS # else # define NON_WINDOWS 1 # endif @@ -172,15 +168,21 @@ typedef pthread_rwlock_t LCMS_RWLOCK_T; # define USE_BIG_ENDIAN 1 #endif -#if defined(__sgi__) || defined(__sgi) || defined(__powerpc__) || defined(sparc) || defined(__ppc__) +#if defined(__sgi__) || defined(__sgi) || defined(__powerpc__) || defined(sparc) || defined(__ppc__) || defined(__s390__) || defined(__s390x__) # define USE_BIG_ENDIAN 1 #endif -#ifdef TARGET_CPU_PPC +#if TARGET_CPU_PPC # define USE_BIG_ENDIAN 1 #endif -#ifdef macintosh +#if macintosh +# ifndef __LITTLE_ENDIAN__ +# define USE_BIG_ENDIAN 1 +# endif +#endif + +#ifdef __BIG_ENDIAN__ # define USE_BIG_ENDIAN 1 #endif @@ -217,11 +219,8 @@ typedef pthread_rwlock_t LCMS_RWLOCK_T; typedef unsigned char BYTE, *LPBYTE; typedef unsigned short WORD, *LPWORD; typedef unsigned long DWORD, *LPDWORD; -typedef int BOOL; typedef char *LPSTR; typedef void *LPVOID; -typedef void* LCMSHANDLE; - #define ZeroMemory(p,l) memset((p),0,(l)) #define CopyMemory(d,s,l) memcpy((d),(s),(l)) @@ -263,8 +262,12 @@ typedef void* LCMSHANDLE; #include -typedef HANDLE LCMSHANDLE; - +#ifdef _WIN64 +# ifdef USE_ASSEMBLER +# undef USE_ASSEMBLER +# define USE_C 1 +# endif +#endif #ifdef USE_INT64 # ifndef LCMSULONGLONG @@ -296,6 +299,10 @@ typedef int LCMS_RWLOCK_T; # define LCMS_UNLOCK(x) #endif +// Base types + +typedef int LCMSBOOL; +typedef void* LCMSHANDLE; #include "icc34.h" // ICC header file @@ -322,16 +329,10 @@ typedef int LCMS_RWLOCK_T; #define icSigMCHEData ((icColorSpaceSignature) 0x4d434845L) // MCHE #define icSigMCHFData ((icColorSpaceSignature) 0x4d434846L) // MCHF -#define icSigCAM97JABData ((icColorSpaceSignature) 0x4A616231L) // 'Jab1' H. Zeng -#define icSigCAM02JABData ((icColorSpaceSignature) 0x4A616232L) // 'Jab2' H. Zeng -#define icSigCAM02JCHData ((icColorSpaceSignature) 0x4A636A32L) // 'Jch2' H. Zeng - #define icSigChromaticityTag ((icTagSignature) 0x6368726dL) // As per Addendum 2 to Spec. ICC.1:1998-09 #define icSigChromaticAdaptationTag ((icTagSignature) 0x63686164L) // 'chad' #define icSigColorantTableTag ((icTagSignature) 0x636c7274L) // 'clrt' #define icSigColorantTableOutTag ((icTagSignature) 0x636c6f74L) // 'clot' -#define icSigHPGamutDescTag ((icTagSignature) 0x676D7441L) // 'gmtA' H. Zeng - #define icSigParametricCurveType ((icTagTypeSignature) 0x70617261L) // parametric (ICC 4.0) #define icSigMultiLocalizedUnicodeType ((icTagTypeSignature) 0x6D6C7563L) @@ -340,7 +341,6 @@ typedef int LCMS_RWLOCK_T; #define icSiglutAtoBType ((icTagTypeSignature) 0x6d414220L) // mAB #define icSiglutBtoAType ((icTagTypeSignature) 0x6d424120L) // mBA #define icSigColorantTableType ((icTagTypeSignature) 0x636c7274L) // clrt -#define icSigHPGamutDescType ((icTagTypeSignature) 0x676D7441L) // gmtA H. Zeng typedef struct { @@ -438,9 +438,6 @@ extern "C" { #ifndef itoa # define itoa _itoa #endif -#ifndef filelength -# define filelength _filelength -#endif #ifndef fileno # define fileno _fileno #endif @@ -450,6 +447,14 @@ extern "C" { #ifndef hypot # define hypot _hypot #endif +#ifndef snprintf +# define snprintf _snprintf +#endif +#ifndef vsnprintf +# define vsnprintf _vsnprintf +#endif + + #endif @@ -470,8 +475,9 @@ typedef LCMSHANDLE cmsHTRANSFORM; // Format of pixel is defined by one DWORD, using bit fields as follows // -// TTTTT U Y F P X S EEE CCCC BBB +// D TTTTT U Y F P X S EEE CCCC BBB // +// D: Use dither (8 bits only) // T: Pixeltype // F: Flavor 0=MinIsBlack(Chocolate) 1=MinIsWhite(Vanilla) // P: Planar? 0=Chunky, 1=Planar @@ -483,6 +489,7 @@ typedef LCMSHANDLE cmsHTRANSFORM; // Y: Swap first - changes ABGR to BGRA and KCMY to CMYK +#define DITHER_SH(s) ((s) << 22) #define COLORSPACE_SH(s) ((s) << 16) #define SWAPFIRST_SH(s) ((s) << 14) #define FLAVOR_SH(s) ((s) << 13) @@ -711,20 +718,20 @@ typedef LCMSHANDLE cmsHTRANSFORM; typedef struct { - unsigned int Crc32; // Has my table been touched? + unsigned int Crc32; // Has my table been touched? - // Keep initial parameters for further serialization + // Keep initial parameters for further serialization int Type; double Params[10]; - } LCMSGAMMAPARAMS, FAR* LPLCMSGAMMAPARAMS; + } LCMSGAMMAPARAMS, FAR* LPLCMSGAMMAPARAMS; // Gamma tables. typedef struct { - LCMSGAMMAPARAMS Seed; // Parameters used for table creation + LCMSGAMMAPARAMS Seed; // Parameters used for table creation // Table-based representation follows @@ -858,7 +865,7 @@ LCMSAPI LPcmsCIExyY LCMSEXPORT cmsD50_xyY(void); LCMSAPI cmsHPROFILE LCMSEXPORT cmsOpenProfileFromFile(const char *ICCProfile, const char *sAccess); LCMSAPI cmsHPROFILE LCMSEXPORT cmsOpenProfileFromMem(LPVOID MemPtr, DWORD dwSize); -LCMSAPI BOOL LCMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile); +LCMSAPI LCMSBOOL LCMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile); // Predefined run-time profiles @@ -915,14 +922,14 @@ LCMSAPI double LCMSEXPORT cmsCIE2000DeltaE(LPcmsCIELab Lab1, LPcmsCIELab LCMSAPI void LCMSEXPORT cmsClampLab(LPcmsCIELab Lab, double amax, double amin, double bmax, double bmin); -LCMSAPI BOOL LCMSEXPORT cmsWhitePointFromTemp(int TempK, LPcmsCIExyY WhitePoint); +LCMSAPI LCMSBOOL LCMSEXPORT cmsWhitePointFromTemp(int TempK, LPcmsCIExyY WhitePoint); -LCMSAPI BOOL LCMSEXPORT cmsAdaptToIlluminant(LPcmsCIEXYZ Result, +LCMSAPI LCMSBOOL LCMSEXPORT cmsAdaptToIlluminant(LPcmsCIEXYZ Result, LPcmsCIEXYZ SourceWhitePt, LPcmsCIEXYZ Illuminant, LPcmsCIEXYZ Value); -LCMSAPI BOOL LCMSEXPORT cmsBuildRGB2XYZtransferMatrix(LPMAT3 r, +LCMSAPI LCMSBOOL LCMSEXPORT cmsBuildRGB2XYZtransferMatrix(LPMAT3 r, LPcmsCIExyY WhitePoint, LPcmsCIExyYTRIPLE Primaries); @@ -976,7 +983,7 @@ LCMSAPI LPGAMMATABLE LCMSEXPORT cmsDupGamma(LPGAMMATABLE Src); LCMSAPI LPGAMMATABLE LCMSEXPORT cmsReverseGamma(int nResultSamples, LPGAMMATABLE InGamma); LCMSAPI LPGAMMATABLE LCMSEXPORT cmsJoinGamma(LPGAMMATABLE InGamma, LPGAMMATABLE OutGamma); LCMSAPI LPGAMMATABLE LCMSEXPORT cmsJoinGammaEx(LPGAMMATABLE InGamma, LPGAMMATABLE OutGamma, int nPoints); -LCMSAPI BOOL LCMSEXPORT cmsSmoothGamma(LPGAMMATABLE Tab, double lambda); +LCMSAPI LCMSBOOL LCMSEXPORT cmsSmoothGamma(LPGAMMATABLE Tab, double lambda); LCMSAPI double LCMSEXPORT cmsEstimateGamma(LPGAMMATABLE t); LCMSAPI double LCMSEXPORT cmsEstimateGammaEx(LPWORD Table, int nEntries, double Thereshold); LCMSAPI LPGAMMATABLE LCMSEXPORT cmsReadICCGamma(cmsHPROFILE hProfile, icTagSignature sig); @@ -984,14 +991,14 @@ LCMSAPI LPGAMMATABLE LCMSEXPORT cmsReadICCGammaReversed(cmsHPROFILE hProfile, i // Access to Profile data. -LCMSAPI BOOL LCMSEXPORT cmsTakeMediaWhitePoint(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile); -LCMSAPI BOOL LCMSEXPORT cmsTakeMediaBlackPoint(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile); -LCMSAPI BOOL LCMSEXPORT cmsTakeIluminant(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile); -LCMSAPI BOOL LCMSEXPORT cmsTakeColorants(LPcmsCIEXYZTRIPLE Dest, cmsHPROFILE hProfile); +LCMSAPI LCMSBOOL LCMSEXPORT cmsTakeMediaWhitePoint(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile); +LCMSAPI LCMSBOOL LCMSEXPORT cmsTakeMediaBlackPoint(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile); +LCMSAPI LCMSBOOL LCMSEXPORT cmsTakeIluminant(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile); +LCMSAPI LCMSBOOL LCMSEXPORT cmsTakeColorants(LPcmsCIEXYZTRIPLE Dest, cmsHPROFILE hProfile); LCMSAPI DWORD LCMSEXPORT cmsTakeHeaderFlags(cmsHPROFILE hProfile); LCMSAPI DWORD LCMSEXPORT cmsTakeHeaderAttributes(cmsHPROFILE hProfile); -LCMSAPI void LCMSEXPORT cmsSetLanguage(int LanguageCode, int CountryCode); +LCMSAPI void LCMSEXPORT cmsSetLanguage(const char LanguageCode[4], const char CountryCode[4]); LCMSAPI const char* LCMSEXPORT cmsTakeProductName(cmsHPROFILE hProfile); LCMSAPI const char* LCMSEXPORT cmsTakeProductDesc(cmsHPROFILE hProfile); LCMSAPI const char* LCMSEXPORT cmsTakeProductInfo(cmsHPROFILE hProfile); @@ -1000,13 +1007,13 @@ LCMSAPI const char* LCMSEXPORT cmsTakeModel(cmsHPROFILE hProfile); LCMSAPI const char* LCMSEXPORT cmsTakeCopyright(cmsHPROFILE hProfile); LCMSAPI const BYTE* LCMSEXPORT cmsTakeProfileID(cmsHPROFILE hProfile); -LCMSAPI BOOL LCMSEXPORT cmsTakeCreationDateTime(struct tm *Dest, cmsHPROFILE hProfile); -LCMSAPI BOOL LCMSEXPORT cmsTakeCalibrationDateTime(struct tm *Dest, cmsHPROFILE hProfile); +LCMSAPI LCMSBOOL LCMSEXPORT cmsTakeCreationDateTime(struct tm *Dest, cmsHPROFILE hProfile); +LCMSAPI LCMSBOOL LCMSEXPORT cmsTakeCalibrationDateTime(struct tm *Dest, cmsHPROFILE hProfile); -LCMSAPI BOOL LCMSEXPORT cmsIsTag(cmsHPROFILE hProfile, icTagSignature sig); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIsTag(cmsHPROFILE hProfile, icTagSignature sig); LCMSAPI int LCMSEXPORT cmsTakeRenderingIntent(cmsHPROFILE hProfile); -LCMSAPI BOOL LCMSEXPORT cmsTakeCharTargetData(cmsHPROFILE hProfile, char** Data, size_t* len); +LCMSAPI LCMSBOOL LCMSEXPORT cmsTakeCharTargetData(cmsHPROFILE hProfile, char** Data, size_t* len); LCMSAPI int LCMSEXPORT cmsReadICCTextEx(cmsHPROFILE hProfile, icTagSignature sig, char *Text, size_t size); LCMSAPI int LCMSEXPORT cmsReadICCText(cmsHPROFILE hProfile, icTagSignature sig, char *Text); @@ -1038,50 +1045,18 @@ LCMSAPI LPcmsSEQ LCMSEXPORT cmsReadProfileSequenceDescription(cmsHPROFILE h LCMSAPI void LCMSEXPORT cmsFreeProfileSequenceDescription(LPcmsSEQ pseq); -// Extended gamut tag -- an HP extension - -#define LCMSGAMUTMETHOD_SEGMENTMAXIMA 0 -#define LCMSGAMUTMETHOD_CONVEXHULL 1 -#define LCMSGAMUTMETHOD_ALPHASHAPE 2 - - -#define LCMSGAMUT_PHYSICAL 0 -#define LCMSGAMUT_HP1 1 -#define LCMSGAMUT_HP2 2 - -typedef struct { - - icColorSpaceSignature CoordSig; // Gamut coordinates signature - icUInt16Number Method; // Method used to generate gamut - icUInt16Number Usage; // Gamut usage or intent - - char Description[LCMS_DESC_MAX]; // Textual description - - cmsViewingConditions Vc; // The viewing conditions - - icUInt32Number Count; // Number of entries - double Data[1]; // The current data - - } cmsGAMUTEX, FAR* LPcmsGAMUTEX; - - -LCMSAPI LPcmsGAMUTEX LCMSEXPORT cmsReadExtendedGamut(cmsHPROFILE hProfile, int index); -LCMSAPI void LCMSEXPORT cmsFreeExtendedGamut(LPcmsGAMUTEX gex); - - - - // Translate form/to our notation to ICC LCMSAPI icColorSpaceSignature LCMSEXPORT _cmsICCcolorSpace(int OurNotation); -LCMSAPI int LCMSEXPORT _cmsLCMScolorSpace(icColorSpaceSignature ProfileSpace); -LCMSAPI int LCMSEXPORT _cmsChannelsOf(icColorSpaceSignature ColorSpace); -LCMSAPI BOOL LCMSEXPORT _cmsIsMatrixShaper(cmsHPROFILE hProfile); +LCMSAPI int LCMSEXPORT _cmsLCMScolorSpace(icColorSpaceSignature ProfileSpace); +LCMSAPI int LCMSEXPORT _cmsChannelsOf(icColorSpaceSignature ColorSpace); +LCMSAPI LCMSBOOL LCMSEXPORT _cmsIsMatrixShaper(cmsHPROFILE hProfile); +// How profiles may be used #define LCMS_USED_AS_INPUT 0 #define LCMS_USED_AS_OUTPUT 1 #define LCMS_USED_AS_PROOF 2 -LCMSAPI BOOL LCMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, int Intent, int UsedDirection); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, int Intent, int UsedDirection); LCMSAPI icColorSpaceSignature LCMSEXPORT cmsGetPCS(cmsHPROFILE hProfile); LCMSAPI icColorSpaceSignature LCMSEXPORT cmsGetColorSpace(cmsHPROFILE hProfile); @@ -1141,7 +1116,7 @@ LCMSAPI void LCMSEXPORT cmsSetProfileID(cmsHPROFILE hProfile, LPBYTE Pr // CRD special -#define cmsFLAGS_NODEFAULTRESOURCEDEF 0x00010000 +#define cmsFLAGS_NODEFAULTRESOURCEDEF 0x01000000 // Gridpoints @@ -1220,9 +1195,9 @@ typedef struct { // Named color support -LCMSAPI int LCMSEXPORT cmsNamedColorCount(cmsHTRANSFORM xform); -LCMSAPI BOOL LCMSEXPORT cmsNamedColorInfo(cmsHTRANSFORM xform, int nColor, char* Name, char* Prefix, char* Suffix); -LCMSAPI int LCMSEXPORT cmsNamedColorIndex(cmsHTRANSFORM xform, const char* Name); +LCMSAPI int LCMSEXPORT cmsNamedColorCount(cmsHTRANSFORM xform); +LCMSAPI LCMSBOOL LCMSEXPORT cmsNamedColorInfo(cmsHTRANSFORM xform, int nColor, char* Name, char* Prefix, char* Suffix); +LCMSAPI int LCMSEXPORT cmsNamedColorIndex(cmsHTRANSFORM xform, const char* Name); // Colorant tables @@ -1230,7 +1205,7 @@ LCMSAPI LPcmsNAMEDCOLORLIST LCMSEXPORT cmsReadColorantTable(cmsHPROFILE hProfile // Profile creation -LCMSAPI BOOL LCMSEXPORT cmsAddTag(cmsHPROFILE hProfile, icTagSignature sig, const void* data); +LCMSAPI LCMSBOOL LCMSEXPORT cmsAddTag(cmsHPROFILE hProfile, icTagSignature sig, const void* data); // Converts a transform to a devicelink profile LCMSAPI cmsHPROFILE LCMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, DWORD dwFlags); @@ -1240,8 +1215,8 @@ LCMSAPI void LCMSEXPORT _cmsSetLUTdepth(cmsHPROFILE hProfile, int depth); // Save profile -LCMSAPI BOOL LCMSEXPORT _cmsSaveProfile(cmsHPROFILE hProfile, const char* FileName); -LCMSAPI BOOL LCMSEXPORT _cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, +LCMSAPI LCMSBOOL LCMSEXPORT _cmsSaveProfile(cmsHPROFILE hProfile, const char* FileName); +LCMSAPI LCMSBOOL LCMSEXPORT _cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, size_t* BytesNeeded); @@ -1286,6 +1261,7 @@ LCMSAPI double LCMSEXPORT cmsEvalLUTreverse(LPLUT Lut, WORD Target[], WORD Resul LCMSAPI LPLUT LCMSEXPORT cmsReadICCLut(cmsHPROFILE hProfile, icTagSignature sig); LCMSAPI LPLUT LCMSEXPORT cmsDupLUT(LPLUT Orig); + // LUT Sampling typedef int (* _cmsSAMPLER)(register WORD In[], @@ -1325,35 +1301,37 @@ LCMSAPI int LCMSEXPORT cmsIT8SetTable(LCMSHANDLE IT8, int nTable); // Persistence LCMSAPI LCMSHANDLE LCMSEXPORT cmsIT8LoadFromFile(const char* cFileName); LCMSAPI LCMSHANDLE LCMSEXPORT cmsIT8LoadFromMem(void *Ptr, size_t len); -LCMSAPI BOOL LCMSEXPORT cmsIT8SaveToFile(LCMSHANDLE IT8, const char* cFileName); -LCMSAPI BOOL LCMSEXPORT cmsIT8SaveToMem(LCMSHANDLE hIT8, void *MemPtr, size_t* BytesNeeded); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SaveToFile(LCMSHANDLE IT8, const char* cFileName); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SaveToMem(LCMSHANDLE hIT8, void *MemPtr, size_t* BytesNeeded); // Properties LCMSAPI const char* LCMSEXPORT cmsIT8GetSheetType(LCMSHANDLE hIT8); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetSheetType(LCMSHANDLE hIT8, const char* Type); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetSheetType(LCMSHANDLE hIT8, const char* Type); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetComment(LCMSHANDLE hIT8, const char* cComment); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetComment(LCMSHANDLE hIT8, const char* cComment); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetPropertyStr(LCMSHANDLE hIT8, const char* cProp, const char *Str); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetPropertyDbl(LCMSHANDLE hIT8, const char* cProp, double Val); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetPropertyHex(LCMSHANDLE hIT8, const char* cProp, int Val); - -LCMSAPI BOOL LCMSEXPORT cmsIT8SetPropertyUncooked(LCMSHANDLE hIT8, const char* Key, const char* Buffer); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyStr(LCMSHANDLE hIT8, const char* cProp, const char *Str); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyDbl(LCMSHANDLE hIT8, const char* cProp, double Val); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyHex(LCMSHANDLE hIT8, const char* cProp, int Val); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyMulti(LCMSHANDLE hIT8, const char* cProp, const char* cSubProp, const char *Val); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyUncooked(LCMSHANDLE hIT8, const char* Key, const char* Buffer); LCMSAPI const char* LCMSEXPORT cmsIT8GetProperty(LCMSHANDLE hIT8, const char* cProp); LCMSAPI double LCMSEXPORT cmsIT8GetPropertyDbl(LCMSHANDLE hIT8, const char* cProp); -LCMSAPI int LCMSEXPORT cmsIT8EnumProperties(LCMSHANDLE IT8, char ***PropertyNames); +LCMSAPI const char* LCMSEXPORT cmsIT8GetPropertyMulti(LCMSHANDLE hIT8, const char* cProp, const char *cSubProp); +LCMSAPI int LCMSEXPORT cmsIT8EnumProperties(LCMSHANDLE hIT8, const char ***PropertyNames); +LCMSAPI int LCMSEXPORT cmsIT8EnumPropertyMulti(LCMSHANDLE hIT8, const char* cProp, const char*** SubpropertyNames); // Datasets LCMSAPI const char* LCMSEXPORT cmsIT8GetDataRowCol(LCMSHANDLE IT8, int row, int col); LCMSAPI double LCMSEXPORT cmsIT8GetDataRowColDbl(LCMSHANDLE IT8, int row, int col); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetDataRowCol(LCMSHANDLE hIT8, int row, int col, +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetDataRowCol(LCMSHANDLE hIT8, int row, int col, const char* Val); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetDataRowColDbl(LCMSHANDLE hIT8, int row, int col, +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetDataRowColDbl(LCMSHANDLE hIT8, int row, int col, double Val); LCMSAPI const char* LCMSEXPORT cmsIT8GetData(LCMSHANDLE IT8, const char* cPatch, const char* cSample); @@ -1361,25 +1339,28 @@ LCMSAPI const char* LCMSEXPORT cmsIT8GetData(LCMSHANDLE IT8, const char* cPa LCMSAPI double LCMSEXPORT cmsIT8GetDataDbl(LCMSHANDLE IT8, const char* cPatch, const char* cSample); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetData(LCMSHANDLE IT8, const char* cPatch, +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetData(LCMSHANDLE IT8, const char* cPatch, const char* cSample, const char *Val); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetDataDbl(LCMSHANDLE hIT8, const char* cPatch, +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetDataDbl(LCMSHANDLE hIT8, const char* cPatch, const char* cSample, double Val); LCMSAPI int LCMSEXPORT cmsIT8GetDataFormat(LCMSHANDLE hIT8, const char* cSample); -LCMSAPI BOOL LCMSEXPORT cmsIT8SetDataFormat(LCMSHANDLE IT8, int n, const char *Sample); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetDataFormat(LCMSHANDLE IT8, int n, const char *Sample); LCMSAPI int LCMSEXPORT cmsIT8EnumDataFormat(LCMSHANDLE IT8, char ***SampleNames); LCMSAPI const char* LCMSEXPORT cmsIT8GetPatchName(LCMSHANDLE hIT8, int nPatch, char* buffer); +LCMSAPI int LCMSEXPORT cmsIT8GetPatchByName(LCMSHANDLE hIT8, const char *cSample); // The LABEL extension LCMSAPI int LCMSEXPORT cmsIT8SetTableByLabel(LCMSHANDLE hIT8, const char* cSet, const char* cField, const char* ExpectedType); +LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetIndexColumn(LCMSHANDLE hIT8, const char* cSample); + // Formatter for double LCMSAPI void LCMSEXPORT cmsIT8DefineDblFormat(LCMSHANDLE IT8, const char* Formatter); @@ -1405,15 +1386,16 @@ LCMSAPI void LCMSEXPORT cmsFloat2XYZEncoded(WORD XYZ[3], const cmsCIEXY // Profiling Extensions --- Would be removed from API in future revisions -LCMSAPI BOOL LCMSEXPORT _cmsAddTextTag(cmsHPROFILE hProfile, icTagSignature sig, const char* Text); -LCMSAPI BOOL LCMSEXPORT _cmsAddXYZTag(cmsHPROFILE hProfile, icTagSignature sig, const cmsCIEXYZ* XYZ); -LCMSAPI BOOL LCMSEXPORT _cmsAddLUTTag(cmsHPROFILE hProfile, icTagSignature sig, const void* lut); -LCMSAPI BOOL LCMSEXPORT _cmsAddGammaTag(cmsHPROFILE hProfile, icTagSignature sig, LPGAMMATABLE TransferFunction); -LCMSAPI BOOL LCMSEXPORT _cmsAddChromaticityTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsCIExyYTRIPLE Chrm); -LCMSAPI BOOL LCMSEXPORT _cmsAddSequenceDescriptionTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsSEQ PSeq); -LCMSAPI BOOL LCMSEXPORT _cmsAddNamedColorTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsNAMEDCOLORLIST nc); -LCMSAPI BOOL LCMSEXPORT _cmsAddDateTimeTag(cmsHPROFILE hProfile, icTagSignature sig, struct tm *DateTime); -LCMSAPI BOOL LCMSEXPORT _cmsAddColorantTableTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsNAMEDCOLORLIST nc); +LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddTextTag(cmsHPROFILE hProfile, icTagSignature sig, const char* Text); +LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddXYZTag(cmsHPROFILE hProfile, icTagSignature sig, const cmsCIEXYZ* XYZ); +LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddLUTTag(cmsHPROFILE hProfile, icTagSignature sig, const void* lut); +LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddGammaTag(cmsHPROFILE hProfile, icTagSignature sig, LPGAMMATABLE TransferFunction); +LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddChromaticityTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsCIExyYTRIPLE Chrm); +LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddSequenceDescriptionTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsSEQ PSeq); +LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddNamedColorTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsNAMEDCOLORLIST nc); +LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddDateTimeTag(cmsHPROFILE hProfile, icTagSignature sig, struct tm *DateTime); +LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddColorantTableTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsNAMEDCOLORLIST nc); +LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddChromaticAdaptationTag(cmsHPROFILE hProfile, icTagSignature sig, const cmsCIEXYZ* mat); // --------------------------------------------------------------------------------------------------- Inline functions @@ -1455,6 +1437,38 @@ LCMS_INLINE WORD _cmsClampWord(int in) return (WORD) in; } +#ifndef LCMS_USER_ALLOC + +// Low-level alloc hook + +LCMS_INLINE void* _cmsMalloc(size_t size) +{ + if (size > ((size_t) 1024*1024*500)) return NULL; // Never allow over 500Mb + if (size < 0) return NULL; // Prevent signed size_t exploits + + return (void*) malloc(size); +} + +LCMS_INLINE void* _cmsCalloc(size_t nmemb, size_t size) +{ + size_t alloc = nmemb * size; + + if (size == 0) { + return _cmsMalloc(0); + } + if (alloc / size != nmemb) { + return NULL; + } + return _cmsMalloc(alloc); +} + +LCMS_INLINE void _cmsFree(void *Ptr) +{ + if (Ptr) free(Ptr); +} + +#endif + // ------------------------------------------------------------------------------------------- end of inline functions // Signal error from inside lcms code @@ -1531,36 +1545,36 @@ typedef struct { // Matrix (Fixed 15.16) -void cdecl VEC3init(LPVEC3 r, double x, double y, double z); // double version -void cdecl VEC3initF(LPWVEC3 r, double x, double y, double z); // Fix32 version -void cdecl VEC3toFix(LPWVEC3 r, LPVEC3 v); -void cdecl VEC3fromFix(LPVEC3 r, LPWVEC3 v); -void cdecl VEC3scaleFix(LPWORD r, LPWVEC3 Scale); -void cdecl VEC3swap(LPVEC3 a, LPVEC3 b); -void cdecl VEC3divK(LPVEC3 r, LPVEC3 v, double d); -void cdecl VEC3perK(LPVEC3 r, LPVEC3 v, double d); -void cdecl VEC3minus(LPVEC3 r, LPVEC3 a, LPVEC3 b); -void cdecl VEC3perComp(LPVEC3 r, LPVEC3 a, LPVEC3 b); -BOOL cdecl VEC3equal(LPWVEC3 a, LPWVEC3 b, double Tolerance); -BOOL cdecl VEC3equalF(LPVEC3 a, LPVEC3 b, double Tolerance); -void cdecl VEC3scaleAndCut(LPWVEC3 r, LPVEC3 v, double d); -void cdecl VEC3cross(LPVEC3 r, LPVEC3 u, LPVEC3 v); -void cdecl VEC3saturate(LPVEC3 v); -double cdecl VEC3distance(LPVEC3 a, LPVEC3 b); -double cdecl VEC3length(LPVEC3 a); +void cdecl VEC3init(LPVEC3 r, double x, double y, double z); // double version +void cdecl VEC3initF(LPWVEC3 r, double x, double y, double z); // Fix32 version +void cdecl VEC3toFix(LPWVEC3 r, LPVEC3 v); +void cdecl VEC3fromFix(LPVEC3 r, LPWVEC3 v); +void cdecl VEC3scaleFix(LPWORD r, LPWVEC3 Scale); +void cdecl VEC3swap(LPVEC3 a, LPVEC3 b); +void cdecl VEC3divK(LPVEC3 r, LPVEC3 v, double d); +void cdecl VEC3perK(LPVEC3 r, LPVEC3 v, double d); +void cdecl VEC3minus(LPVEC3 r, LPVEC3 a, LPVEC3 b); +void cdecl VEC3perComp(LPVEC3 r, LPVEC3 a, LPVEC3 b); +LCMSBOOL cdecl VEC3equal(LPWVEC3 a, LPWVEC3 b, double Tolerance); +LCMSBOOL cdecl VEC3equalF(LPVEC3 a, LPVEC3 b, double Tolerance); +void cdecl VEC3scaleAndCut(LPWVEC3 r, LPVEC3 v, double d); +void cdecl VEC3cross(LPVEC3 r, LPVEC3 u, LPVEC3 v); +void cdecl VEC3saturate(LPVEC3 v); +double cdecl VEC3distance(LPVEC3 a, LPVEC3 b); +double cdecl VEC3length(LPVEC3 a); -void cdecl MAT3identity(LPMAT3 a); -void cdecl MAT3per(LPMAT3 r, LPMAT3 a, LPMAT3 b); -void cdecl MAT3perK(LPMAT3 r, LPMAT3 v, double d); -int cdecl MAT3inverse(LPMAT3 a, LPMAT3 b); -BOOL cdecl MAT3solve(LPVEC3 x, LPMAT3 a, LPVEC3 b); -double cdecl MAT3det(LPMAT3 m); -void cdecl MAT3eval(LPVEC3 r, LPMAT3 a, LPVEC3 v); -void cdecl MAT3toFix(LPWMAT3 r, LPMAT3 v); -void cdecl MAT3fromFix(LPMAT3 r, LPWMAT3 v); -void cdecl MAT3evalW(LPWVEC3 r, LPWMAT3 a, LPWVEC3 v); -BOOL cdecl MAT3isIdentity(LPWMAT3 a, double Tolerance); -void cdecl MAT3scaleAndCut(LPWMAT3 r, LPMAT3 v, double d); +void cdecl MAT3identity(LPMAT3 a); +void cdecl MAT3per(LPMAT3 r, LPMAT3 a, LPMAT3 b); +void cdecl MAT3perK(LPMAT3 r, LPMAT3 v, double d); +int cdecl MAT3inverse(LPMAT3 a, LPMAT3 b); +LCMSBOOL cdecl MAT3solve(LPVEC3 x, LPMAT3 a, LPVEC3 b); +double cdecl MAT3det(LPMAT3 m); +void cdecl MAT3eval(LPVEC3 r, LPMAT3 a, LPVEC3 v); +void cdecl MAT3toFix(LPWMAT3 r, LPMAT3 v); +void cdecl MAT3fromFix(LPMAT3 r, LPWMAT3 v); +void cdecl MAT3evalW(LPWVEC3 r, LPWMAT3 a, LPWVEC3 v); +LCMSBOOL cdecl MAT3isIdentity(LPWMAT3 a, double Tolerance); +void cdecl MAT3scaleAndCut(LPWMAT3 r, LPMAT3 v, double d); // Is a table linear? @@ -1608,7 +1622,7 @@ typedef struct _lcms_l16params_struc { // Used on 16 bits interpolations void cdecl cmsCalcL16Params(int nSamples, LPL16PARAMS p); void cdecl cmsCalcCLUT16Params(int nSamples, int InputChan, int OutputChan, LPL16PARAMS p); void cdecl cmsCalcCLUT16ParamsEx(int nSamples, int InputChan, int OutputChan, - BOOL lUseTetrahedral, LPL16PARAMS p); + LCMSBOOL lUseTetrahedral, LPL16PARAMS p); WORD cdecl cmsLinearInterpLUT16(WORD Value, WORD LutTable[], LPL16PARAMS p); Fixed32 cdecl cmsLinearInterpFixed(WORD Value1, WORD LutTable[], LPL16PARAMS p); @@ -1692,18 +1706,18 @@ struct _lcms_LUT_struc { // Gray axes fixup. Only on v2 8-bit Lab LUT - BOOL FixGrayAxes; + LCMSBOOL FixGrayAxes; - // Parameters used for curve creation + // Parameters used for curve creation - LCMSGAMMAPARAMS LCurvesSeed[4][MAXCHANNELS]; + LCMSGAMMAPARAMS LCurvesSeed[4][MAXCHANNELS]; }; // LUT, FAR* LPLUT; -BOOL cdecl _cmsSmoothEndpoints(LPWORD Table, int nEntries); +LCMSBOOL cdecl _cmsSmoothEndpoints(LPWORD Table, int nEntries); // CRC of gamma tables @@ -1721,7 +1735,7 @@ LPGAMMATABLE cdecl cmsConvertSampledCurveToGamma(LPSAMPLEDCURVE Sampled, doubl void cdecl cmsEndpointsOfSampledCurve(LPSAMPLEDCURVE p, double* Min, double* Max); void cdecl cmsClampSampledCurve(LPSAMPLEDCURVE p, double Min, double Max); -BOOL cdecl cmsSmoothSampledCurve(LPSAMPLEDCURVE Tab, double SmoothingLambda); +LCMSBOOL cdecl cmsSmoothSampledCurve(LPSAMPLEDCURVE Tab, double SmoothingLambda); void cdecl cmsRescaleSampledCurve(LPSAMPLEDCURVE p, double Min, double Max, int nPoints); LPSAMPLEDCURVE cdecl cmsJoinSampledCurves(LPSAMPLEDCURVE X, LPSAMPLEDCURVE Y, int nResultingPoints); @@ -1755,19 +1769,19 @@ LPMATSHAPER cdecl cmsAllocMatShaper2(LPMAT3 matrix, LPGAMMATABLE In[], LPGAMMATA void cdecl cmsFreeMatShaper(LPMATSHAPER MatShaper); void cdecl cmsEvalMatShaper(LPMATSHAPER MatShaper, WORD In[], WORD Out[]); -BOOL cdecl cmsReadICCMatrixRGB2XYZ(LPMAT3 r, cmsHPROFILE hProfile); +LCMSBOOL cdecl cmsReadICCMatrixRGB2XYZ(LPMAT3 r, cmsHPROFILE hProfile); -LPMATSHAPER cdecl cmsBuildInputMatrixShaper(cmsHPROFILE InputProfile); -LPMATSHAPER cdecl cmsBuildOutputMatrixShaper(cmsHPROFILE OutputProfile); +LPMATSHAPER cdecl cmsBuildInputMatrixShaper(cmsHPROFILE InputProfile); +LPMATSHAPER cdecl cmsBuildOutputMatrixShaper(cmsHPROFILE OutputProfile); // White Point & Primary chromas handling -BOOL cdecl cmsAdaptationMatrix(LPMAT3 r, LPMAT3 ConeMatrix, LPcmsCIEXYZ FromIll, LPcmsCIEXYZ ToIll); -BOOL cdecl cmsAdaptMatrixToD50(LPMAT3 r, LPcmsCIExyY SourceWhitePt); -BOOL cdecl cmsAdaptMatrixFromD50(LPMAT3 r, LPcmsCIExyY DestWhitePt); +LCMSBOOL cdecl cmsAdaptationMatrix(LPMAT3 r, LPMAT3 ConeMatrix, LPcmsCIEXYZ FromIll, LPcmsCIEXYZ ToIll); +LCMSBOOL cdecl cmsAdaptMatrixToD50(LPMAT3 r, LPcmsCIExyY SourceWhitePt); +LCMSBOOL cdecl cmsAdaptMatrixFromD50(LPMAT3 r, LPcmsCIExyY DestWhitePt); -BOOL cdecl cmsReadChromaticAdaptationMatrix(LPMAT3 r, cmsHPROFILE hProfile); +LCMSBOOL cdecl cmsReadChromaticAdaptationMatrix(LPMAT3 r, cmsHPROFILE hProfile); // Inter-PCS conversion routines. They assume D50 as white point. void cdecl cmsXYZ2LabEncoded(WORD XYZ[3], WORD Lab[3]); @@ -1782,7 +1796,7 @@ WORD cdecl _cmsQuantizeVal(double i, int MaxSamples); LPcmsNAMEDCOLORLIST cdecl cmsAllocNamedColorList(int n); int cdecl cmsReadICCnamedColorList(cmsHTRANSFORM xform, cmsHPROFILE hProfile, icTagSignature sig); void cdecl cmsFreeNamedColorList(LPcmsNAMEDCOLORLIST List); -BOOL cdecl cmsAppendNamedColor(cmsHTRANSFORM xform, const char* Name, WORD PCS[3], WORD Colorant[MAXCHANNELS]); +LCMSBOOL cdecl cmsAppendNamedColor(cmsHTRANSFORM xform, const char* Name, WORD PCS[3], WORD Colorant[MAXCHANNELS]); // I/O @@ -1804,7 +1818,7 @@ typedef struct _lcms_iccprofile_struct { icColorSpaceSignature PCS; icRenderingIntent RenderingIntent; icUInt32Number flags; - icUInt32Number attributes; + icUInt32Number attributes; cmsCIEXYZ Illuminant; // Additions for V4 profiles @@ -1826,23 +1840,23 @@ typedef struct _lcms_iccprofile_struct { char PhysicalFile[MAX_PATH]; - BOOL IsWrite; - BOOL SaveAs8Bits; + LCMSBOOL IsWrite; + LCMSBOOL SaveAs8Bits; struct tm Created; // I/O handlers - size_t (* Read)(void *buffer, size_t size, size_t count, struct _lcms_iccprofile_struct* Icc); + size_t (* Read)(void *buffer, size_t size, size_t count, struct _lcms_iccprofile_struct* Icc); - BOOL (* Seek)(struct _lcms_iccprofile_struct* Icc, size_t offset); - BOOL (* Close)(struct _lcms_iccprofile_struct* Icc); - size_t (* Tell)(struct _lcms_iccprofile_struct* Icc); - BOOL (* Grow)(struct _lcms_iccprofile_struct* Icc, size_t amount); + LCMSBOOL (* Seek)(struct _lcms_iccprofile_struct* Icc, size_t offset); + LCMSBOOL (* Close)(struct _lcms_iccprofile_struct* Icc); + size_t (* Tell)(struct _lcms_iccprofile_struct* Icc); + LCMSBOOL (* Grow)(struct _lcms_iccprofile_struct* Icc, size_t amount); // Writting - BOOL (* Write)(struct _lcms_iccprofile_struct* Icc, size_t size, LPVOID Ptr); + LCMSBOOL (* Write)(struct _lcms_iccprofile_struct* Icc, size_t size, LPVOID Ptr); size_t UsedSpace; @@ -1854,7 +1868,7 @@ typedef struct _lcms_iccprofile_struct { cmsHPROFILE cdecl _cmsCreateProfilePlaceholder(void); // Search into tag dictionary -icInt32Number cdecl _cmsSearchTag(LPLCMSICCPROFILE Profile, icTagSignature sig, BOOL lSignalError); +icInt32Number cdecl _cmsSearchTag(LPLCMSICCPROFILE Profile, icTagSignature sig, LCMSBOOL lSignalError); // Search for a particular tag, replace if found or add new one else LPVOID _cmsInitTag(LPLCMSICCPROFILE Icc, icTagSignature sig, size_t size, const void* Init); @@ -1870,6 +1884,7 @@ void _cmsSetSaveToMemory(LPLCMSICCPROFILE Icc, LPVOID MemPtr, size_t dwSize); // These macros unpack format specifiers into integers +#define T_DITHER(s) (((s)>>22)&1) #define T_COLORSPACE(s) (((s)>>16)&31) #define T_SWAPFIRST(s) (((s)>>14)&1) #define T_FLAVOR(s) (((s)>>13)&1) @@ -1966,7 +1981,7 @@ typedef struct _cmstransform_struct { // Flag for transform involving v4 profiles - BOOL lInputV4Lab, lOutputV4Lab; + LCMSBOOL lInputV4Lab, lOutputV4Lab; // 1-pixel cache @@ -1976,7 +1991,7 @@ typedef struct _cmstransform_struct { double AdaptationState; // Figure for v4 incomplete state of adaptation - LCMS_RWLOCK_T rwlock; + LCMS_RWLOCK_T rwlock; } _cmsTRANSFORM,FAR *_LPcmsTRANSFORM; @@ -2013,7 +2028,7 @@ int cdecl cmsChooseCnvrt(int Absolute, // Clamping & Gamut handling -BOOL cdecl _cmsEndPointsBySpace(icColorSpaceSignature Space, +LCMSBOOL cdecl _cmsEndPointsBySpace(icColorSpaceSignature Space, WORD **White, WORD **Black, int *nOutputs); WORD * cdecl _cmsWhiteBySpace(icColorSpaceSignature Space); @@ -2042,7 +2057,7 @@ LPLUT _cmsPrecalculateBlackPreservingDeviceLink(cmsHTRANSFORM hCMYK2CMYK, DWORD LPLUT cdecl _cmsPrecalculateGamutCheck(cmsHTRANSFORM h); // Hot fixes bad profiles -BOOL cdecl _cmsFixWhiteMisalignment(_LPcmsTRANSFORM p); +LCMSBOOL cdecl _cmsFixWhiteMisalignment(_LPcmsTRANSFORM p); // Marks LUT as 8 bit on input LPLUT cdecl _cmsBlessLUT8(LPLUT Lut); @@ -2060,6 +2075,10 @@ void cdecl _cmsComputePrelinearizationTablesFromXFORM(cmsHTRANSFORM h[], int nTr // Build a tone curve for K->K' if possible (only works on CMYK) LPGAMMATABLE _cmsBuildKToneCurve(cmsHTRANSFORM hCMYK2CMYK, int nPoints); +// Validates a LUT +LCMSBOOL cdecl _cmsValidateLUT(LPLUT NewLUT); + + // These are two VITAL macros, from converting between 8 and 16 bit // representation. @@ -2077,3 +2096,4 @@ LPGAMMATABLE _cmsBuildKToneCurve(cmsHTRANSFORM hCMYK2CMYK, int nPoints); #endif #endif + From b2f54efed2d4041925064131ecf815e9d5555be6 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Tue, 24 Mar 2009 10:53:04 -0700 Subject: [PATCH 44/75] 6821504: typo in lcmsio.c Reviewed-by: jgodinez --- jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c index 602a3eb943b..7f8cbf06779 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c @@ -190,7 +190,7 @@ LCMSBOOL MemoryGrow(struct _lcms_iccprofile_struct* Icc, size_t size) /* Follow same policies as functions in lcms.h */ if (ResData->Size + size < 0) return NULL; - if (ResData->Size + size > (size_t)1024*1024*500))) return NULL; + if (ResData->Size + size > ((size_t)1024*1024*500)) return NULL; newBlock = realloc(ResData->Block, ResData->Size + size); From ab419e86a9333761e8a5dac71174dddd8090d249 Mon Sep 17 00:00:00 2001 From: Kelly O'Hair Date: Thu, 26 Mar 2009 16:48:03 -0700 Subject: [PATCH 45/75] 6822913: Consolidate make/jprt.config files, let JPRT manage this file make it optional in repos Reviewed-by: tbell --- jaxp/make/jprt.config | 241 ------------------------------------------ 1 file changed, 241 deletions(-) delete mode 100644 jaxp/make/jprt.config diff --git a/jaxp/make/jprt.config b/jaxp/make/jprt.config deleted file mode 100644 index 90200b1bc41..00000000000 --- a/jaxp/make/jprt.config +++ /dev/null @@ -1,241 +0,0 @@ -#!echo "This is not a shell script" -############################################################################# -# -# Copyright 2006 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. Sun designates this -# particular file as subject to the "Classpath" exception as provided -# by Sun in the LICENSE file that accompanied this code. -# -# 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. -# -############################################################################# -# -# JPRT shell configuration for building. -# -# Input environment variables: -# ALT_BOOTDIR -# ALT_SLASH_JAVA -# ALT_JDK_IMPORT_PATH -# Windows Only: -# PATH -# PROCESSOR_IDENTIFIER -# ROOTDIR -# -# Output variable settings: -# make Full path to GNU make -# -# Output environment variables: -# PATH -# Windows Only: -# ALT_DEVTOOLS_PATH (To avoid the C:/UTILS default) -# -# After JDK6, most settings will be found via ALT_SLASH_JAVA or -# by way of other system environment variables. If this was JDK5 -# or an older JDK, you might need to export more ALT_* variables. -# -############################################################################# - -############################################################################# -# Error -error() # message -{ - echo "ERROR: $1" - exit 6 -} -# Directory must exist -dirMustExist() # dir name -{ - if [ ! -d "$1" ] ; then - error "Directory for $2 does not exist: $1" - fi -} -# File must exist -fileMustExist() # dir name -{ - if [ ! -f "$1" ] ; then - error "File for $2 does not exist: $1" - fi -} -############################################################################# - -# Should be set by JPRT as the 3 basic inputs -bootdir="${ALT_BOOTDIR}" -slashjava="${ALT_SLASH_JAVA}" -jdk_import="${ALT_JDK_IMPORT_PATH}" - -# Check input -dirMustExist "${bootdir}" ALT_BOOTDIR -dirMustExist "${slashjava}" ALT_SLASH_JAVA -dirMustExist "${jdk_import}" ALT_JDK_IMPORT_PATH - -# Uses 'uname -s', but only expect SunOS or Linux, assume Windows otherwise. -osname=`uname -s` -if [ "${osname}" = SunOS ] ; then - - # SOLARIS: Sparc or X86 - osarch=`uname -p` - if [ "${osarch}" = sparc ] ; then - solaris_arch=sparc - else - solaris_arch=i386 - fi - - # Add basic solaris system paths - path4sdk=/usr/ccs/bin:/usr/ccs/lib:/usr/bin:/bin:/usr/sfw/bin - - # Get the previous JDK to be used to bootstrap the build - path4sdk=${bootdir}/bin:${path4sdk} - - # Ant - ANT_HOME=${slashjava}/devtools/share/ant/1.7.0 - export ANT_HOME - antbindir=${ANT_HOME}/bin - fileMustExist "${antbindir}/ant" ant - path4sdk=${antbindir}:${path4sdk} - - # Find GNU make - make=/usr/sfw/bin/gmake - if [ ! -f ${make} ] ; then - make=/opt/sfw/bin/gmake - if [ ! -f ${make} ] ; then - make=${slashjava}/devtools/${solaris_arch}/bin/gnumake - fi - fi - fileMustExist "${make}" make - - # File creation mask - umask 002 - -elif [ "${osname}" = Linux ] ; then - - # LINUX: X86, AMD64 - osarch=`uname -m` - if [ "${osarch}" = i686 ] ; then - linux_arch=i586 - elif [ "${osarch}" = x86_64 ] ; then - linux_arch=amd64 - fi - - # Add basic paths - path4sdk=/usr/bin:/bin:/usr/sbin:/sbin - - # Get the previous JDK to be used to bootstrap the build - path4sdk=${bootdir}/bin:${path4sdk} - - # Ant - ANT_HOME=${slashjava}/devtools/share/ant/1.7.0 - export ANT_HOME - antbindir=${ANT_HOME}/bin - fileMustExist "${antbindir}/ant" ant - path4sdk=${antbindir}:${path4sdk} - - # Find GNU make - make=/usr/bin/make - fileMustExist "${make}" make - - umask 002 - -else - - # Windows: Differs on CYGWIN vs. MKS. - # Also, blanks in pathnames gives GNU make headaches, so anything placed - # in any ALT_* variable should be the short windows dosname. - - # WINDOWS: Install and use MKS or CYGWIN (should have already been done) - # Assumption here is that you are in a shell window via MKS or cygwin. - # MKS install should have defined the environment variable ROOTDIR. - # We also need to figure out which one we have: X86, AMD64 - if [ "`echo ${PROCESSOR_IDENTIFIER} | fgrep AMD64`" != "" ] ; then - windows_arch=amd64 - else - windows_arch=i586 - fi - - # We need to determine if we are running a CYGWIN shell or an MKS shell - # (if uname isn't available, then it will be unix_toolset=unknown) - unix_toolset=unknown - if [ "`uname -a | fgrep Cygwin`" = "" -a -d "${ROOTDIR}" ] ; then - # We kind of assume ROOTDIR is where MKS is and it's ok - unix_toolset=MKS - mkshome=`dosname -s "${ROOTDIR}"` - # Utility to convert to short pathnames without spaces - dosname="${mkshome}/mksnt/dosname -s" - # Most unix utilities are in the mksnt directory of ROOTDIR - unixcommand_path="${mkshome}/mksnt" - path4sdk="${unixcommand_path}" - dirMustExist "${unixcommand_path}" ALT_UNIXCOMMAND_PATH - devtools_path="${slashjava}/devtools/win32/bin" - path4sdk="${devtools_path};${path4sdk}" - # Normally this need not be set, but on Windows it's default is C:/UTILS - ALT_DEVTOOLS_PATH="${devtools_path}" - export ALT_DEVTOOLS_PATH - dirMustExist "${devtools_path}" ALT_DEVTOOLS_PATH - # Find GNU make - make="${devtools_path}/gnumake.exe" - fileMustExist "${make}" make - elif [ "`uname -a | fgrep Cygwin`" != "" -a -f /bin/cygpath ] ; then - # For CYGWIN, uname will have "Cygwin" in it, and /bin/cygpath should exist - unix_toolset=CYGWIN - # Utility to convert to short pathnames without spaces - dosname="/usr/bin/cygpath -a -m -s" - # Most unix utilities are in the /usr/bin - unixcommand_path="/usr/bin" - path4sdk="${unixcommand_path}" - dirMustExist "${unixcommand_path}" ALT_UNIXCOMMAND_PATH - # Find GNU make - make="${unixcommand_path}/make.exe" - fileMustExist "${make}" make - else - echo "WARNING: Cannot figure out if this is MKS or CYGWIN" - fi - - # WINDOWS: Get the previous JDK to be used to bootstrap the build - path4sdk="${bootdir}/bin;${path4sdk}" - - # Ant - ANT_HOME=${slashjava}/devtools/share/ant/1.7.0 - export ANT_HOME - antbindir=${ANT_HOME}/bin - fileMustExist "${antbindir}/ant" ant - path4sdk="${antbindir};${path4sdk}" - - # Turn all \\ into /, remove duplicates and trailing / - slash_path="`echo ${path4sdk} | sed -e 's@\\\\@/@g' -e 's@//@/@g' -e 's@/$@@' -e 's@/;@;@g'`" - - # For windows, it's hard to know where the system is, so we just add this - # to PATH. - path4sdk="${slash_path};${PATH}" - - # Convert path4sdk to cygwin style - if [ "${unix_toolset}" = CYGWIN ] ; then - path4sdk="`/usr/bin/cygpath -p ${path4sdk}`" - fi - -fi - -# Export PATH setting -PATH="${path4sdk}" -export PATH - -# Things we need to unset -unset LD_LIBRARY_PATH -unset LD_LIBRARY_PATH_32 -unset LD_LIBRARY_PATH_64 -unset JAVA_HOME - From 7bb1e5eae12579b28e9b82ba45d0b66ff5c968c3 Mon Sep 17 00:00:00 2001 From: Kelly O'Hair Date: Thu, 26 Mar 2009 16:48:29 -0700 Subject: [PATCH 46/75] 6822913: Consolidate make/jprt.config files, let JPRT manage this file make it optional in repos Reviewed-by: tbell --- jaxws/make/jprt.config | 241 ----------------------------------------- 1 file changed, 241 deletions(-) delete mode 100644 jaxws/make/jprt.config diff --git a/jaxws/make/jprt.config b/jaxws/make/jprt.config deleted file mode 100644 index 90200b1bc41..00000000000 --- a/jaxws/make/jprt.config +++ /dev/null @@ -1,241 +0,0 @@ -#!echo "This is not a shell script" -############################################################################# -# -# Copyright 2006 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. Sun designates this -# particular file as subject to the "Classpath" exception as provided -# by Sun in the LICENSE file that accompanied this code. -# -# 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. -# -############################################################################# -# -# JPRT shell configuration for building. -# -# Input environment variables: -# ALT_BOOTDIR -# ALT_SLASH_JAVA -# ALT_JDK_IMPORT_PATH -# Windows Only: -# PATH -# PROCESSOR_IDENTIFIER -# ROOTDIR -# -# Output variable settings: -# make Full path to GNU make -# -# Output environment variables: -# PATH -# Windows Only: -# ALT_DEVTOOLS_PATH (To avoid the C:/UTILS default) -# -# After JDK6, most settings will be found via ALT_SLASH_JAVA or -# by way of other system environment variables. If this was JDK5 -# or an older JDK, you might need to export more ALT_* variables. -# -############################################################################# - -############################################################################# -# Error -error() # message -{ - echo "ERROR: $1" - exit 6 -} -# Directory must exist -dirMustExist() # dir name -{ - if [ ! -d "$1" ] ; then - error "Directory for $2 does not exist: $1" - fi -} -# File must exist -fileMustExist() # dir name -{ - if [ ! -f "$1" ] ; then - error "File for $2 does not exist: $1" - fi -} -############################################################################# - -# Should be set by JPRT as the 3 basic inputs -bootdir="${ALT_BOOTDIR}" -slashjava="${ALT_SLASH_JAVA}" -jdk_import="${ALT_JDK_IMPORT_PATH}" - -# Check input -dirMustExist "${bootdir}" ALT_BOOTDIR -dirMustExist "${slashjava}" ALT_SLASH_JAVA -dirMustExist "${jdk_import}" ALT_JDK_IMPORT_PATH - -# Uses 'uname -s', but only expect SunOS or Linux, assume Windows otherwise. -osname=`uname -s` -if [ "${osname}" = SunOS ] ; then - - # SOLARIS: Sparc or X86 - osarch=`uname -p` - if [ "${osarch}" = sparc ] ; then - solaris_arch=sparc - else - solaris_arch=i386 - fi - - # Add basic solaris system paths - path4sdk=/usr/ccs/bin:/usr/ccs/lib:/usr/bin:/bin:/usr/sfw/bin - - # Get the previous JDK to be used to bootstrap the build - path4sdk=${bootdir}/bin:${path4sdk} - - # Ant - ANT_HOME=${slashjava}/devtools/share/ant/1.7.0 - export ANT_HOME - antbindir=${ANT_HOME}/bin - fileMustExist "${antbindir}/ant" ant - path4sdk=${antbindir}:${path4sdk} - - # Find GNU make - make=/usr/sfw/bin/gmake - if [ ! -f ${make} ] ; then - make=/opt/sfw/bin/gmake - if [ ! -f ${make} ] ; then - make=${slashjava}/devtools/${solaris_arch}/bin/gnumake - fi - fi - fileMustExist "${make}" make - - # File creation mask - umask 002 - -elif [ "${osname}" = Linux ] ; then - - # LINUX: X86, AMD64 - osarch=`uname -m` - if [ "${osarch}" = i686 ] ; then - linux_arch=i586 - elif [ "${osarch}" = x86_64 ] ; then - linux_arch=amd64 - fi - - # Add basic paths - path4sdk=/usr/bin:/bin:/usr/sbin:/sbin - - # Get the previous JDK to be used to bootstrap the build - path4sdk=${bootdir}/bin:${path4sdk} - - # Ant - ANT_HOME=${slashjava}/devtools/share/ant/1.7.0 - export ANT_HOME - antbindir=${ANT_HOME}/bin - fileMustExist "${antbindir}/ant" ant - path4sdk=${antbindir}:${path4sdk} - - # Find GNU make - make=/usr/bin/make - fileMustExist "${make}" make - - umask 002 - -else - - # Windows: Differs on CYGWIN vs. MKS. - # Also, blanks in pathnames gives GNU make headaches, so anything placed - # in any ALT_* variable should be the short windows dosname. - - # WINDOWS: Install and use MKS or CYGWIN (should have already been done) - # Assumption here is that you are in a shell window via MKS or cygwin. - # MKS install should have defined the environment variable ROOTDIR. - # We also need to figure out which one we have: X86, AMD64 - if [ "`echo ${PROCESSOR_IDENTIFIER} | fgrep AMD64`" != "" ] ; then - windows_arch=amd64 - else - windows_arch=i586 - fi - - # We need to determine if we are running a CYGWIN shell or an MKS shell - # (if uname isn't available, then it will be unix_toolset=unknown) - unix_toolset=unknown - if [ "`uname -a | fgrep Cygwin`" = "" -a -d "${ROOTDIR}" ] ; then - # We kind of assume ROOTDIR is where MKS is and it's ok - unix_toolset=MKS - mkshome=`dosname -s "${ROOTDIR}"` - # Utility to convert to short pathnames without spaces - dosname="${mkshome}/mksnt/dosname -s" - # Most unix utilities are in the mksnt directory of ROOTDIR - unixcommand_path="${mkshome}/mksnt" - path4sdk="${unixcommand_path}" - dirMustExist "${unixcommand_path}" ALT_UNIXCOMMAND_PATH - devtools_path="${slashjava}/devtools/win32/bin" - path4sdk="${devtools_path};${path4sdk}" - # Normally this need not be set, but on Windows it's default is C:/UTILS - ALT_DEVTOOLS_PATH="${devtools_path}" - export ALT_DEVTOOLS_PATH - dirMustExist "${devtools_path}" ALT_DEVTOOLS_PATH - # Find GNU make - make="${devtools_path}/gnumake.exe" - fileMustExist "${make}" make - elif [ "`uname -a | fgrep Cygwin`" != "" -a -f /bin/cygpath ] ; then - # For CYGWIN, uname will have "Cygwin" in it, and /bin/cygpath should exist - unix_toolset=CYGWIN - # Utility to convert to short pathnames without spaces - dosname="/usr/bin/cygpath -a -m -s" - # Most unix utilities are in the /usr/bin - unixcommand_path="/usr/bin" - path4sdk="${unixcommand_path}" - dirMustExist "${unixcommand_path}" ALT_UNIXCOMMAND_PATH - # Find GNU make - make="${unixcommand_path}/make.exe" - fileMustExist "${make}" make - else - echo "WARNING: Cannot figure out if this is MKS or CYGWIN" - fi - - # WINDOWS: Get the previous JDK to be used to bootstrap the build - path4sdk="${bootdir}/bin;${path4sdk}" - - # Ant - ANT_HOME=${slashjava}/devtools/share/ant/1.7.0 - export ANT_HOME - antbindir=${ANT_HOME}/bin - fileMustExist "${antbindir}/ant" ant - path4sdk="${antbindir};${path4sdk}" - - # Turn all \\ into /, remove duplicates and trailing / - slash_path="`echo ${path4sdk} | sed -e 's@\\\\@/@g' -e 's@//@/@g' -e 's@/$@@' -e 's@/;@;@g'`" - - # For windows, it's hard to know where the system is, so we just add this - # to PATH. - path4sdk="${slash_path};${PATH}" - - # Convert path4sdk to cygwin style - if [ "${unix_toolset}" = CYGWIN ] ; then - path4sdk="`/usr/bin/cygpath -p ${path4sdk}`" - fi - -fi - -# Export PATH setting -PATH="${path4sdk}" -export PATH - -# Things we need to unset -unset LD_LIBRARY_PATH -unset LD_LIBRARY_PATH_32 -unset LD_LIBRARY_PATH_64 -unset JAVA_HOME - From 69c8b43f099f6472a1018d84b2535d3ee9fb0437 Mon Sep 17 00:00:00 2001 From: Kelly O'Hair Date: Thu, 26 Mar 2009 16:48:53 -0700 Subject: [PATCH 47/75] 6822913: Consolidate make/jprt.config files, let JPRT manage this file make it optional in repos Reviewed-by: tbell --- langtools/make/jprt.config | 241 ------------------------------------- 1 file changed, 241 deletions(-) delete mode 100644 langtools/make/jprt.config diff --git a/langtools/make/jprt.config b/langtools/make/jprt.config deleted file mode 100644 index b112bcb1eda..00000000000 --- a/langtools/make/jprt.config +++ /dev/null @@ -1,241 +0,0 @@ -#!echo "This is not a shell script" -############################################################################# -# -# Copyright 2006 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. Sun designates this -# particular file as subject to the "Classpath" exception as provided -# by Sun in the LICENSE file that accompanied this code. -# -# 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. -# -############################################################################# -# -# JPRT shell configuration for building. -# -# Input environment variables: -# ALT_BOOTDIR -# ALT_SLASH_JAVA -# ALT_JDK_IMPORT_PATH -# Windows Only: -# PATH -# PROCESSOR_IDENTIFIER -# ROOTDIR -# -# Output variable settings: -# make Full path to GNU make -# -# Output environment variables: -# PATH -# Windows Only: -# ALT_DEVTOOLS_PATH (To avoid the C:/UTILS default) -# -# After JDK6, most settings will be found via ALT_SLASH_JAVA or -# by way of other system environment variables. If this was JDK5 -# or an older JDK, you might need to export more ALT_* variables. -# -############################################################################# - -############################################################################# -# Error -error() # message -{ - echo "ERROR: $1" - exit 6 -} -# Directory must exist -dirMustExist() # dir name -{ - if [ ! -d "$1" ] ; then - error "Directory for $2 does not exist: $1" - fi -} -# File must exist -fileMustExist() # dir name -{ - if [ ! -f "$1" ] ; then - error "File for $2 does not exist: $1" - fi -} -############################################################################# - -# Should be set by JPRT as the 3 basic inputs -bootdir="${ALT_BOOTDIR}" -slashjava="${ALT_SLASH_JAVA}" -jdk_import="${ALT_JDK_IMPORT_PATH}" - -# Check input -dirMustExist "${bootdir}" ALT_BOOTDIR -dirMustExist "${slashjava}" ALT_SLASH_JAVA -dirMustExist "${jdk_import}" ALT_JDK_IMPORT_PATH - -# Uses 'uname -s', but only expect SunOS or Linux, assume Windows otherwise. -osname=`uname -s` -if [ "${osname}" = SunOS ] ; then - - # SOLARIS: Sparc or X86 - osarch=`uname -p` - if [ "${osarch}" = sparc ] ; then - solaris_arch=sparc - else - solaris_arch=i386 - fi - - # Add basic solaris system paths - path4sdk=/usr/ccs/bin:/usr/ccs/lib:/usr/bin:/bin:/usr/sfw/bin - - # Get the previous JDK to be used to bootstrap the build - path4sdk=${bootdir}/bin:${path4sdk} - - # Ant - ANT_HOME=${slashjava}/devtools/share/ant/1.7.0 - export ANT_HOME - antbindir=${ANT_HOME}/bin - fileMustExist "${antbindir}/ant" ant - path4sdk=${antbindir}:${path4sdk} - - # Find GNU make - make=/usr/sfw/bin/gmake - if [ ! -f ${make} ] ; then - make=/opt/sfw/bin/gmake - if [ ! -f ${make} ] ; then - make=${slashjava}/devtools/${solaris_arch}/bin/gnumake - fi - fi - fileMustExist "${make}" make - - # File creation mask - umask 002 - -elif [ "${osname}" = Linux ] ; then - - # LINUX: X86, AMD64 - osarch=`uname -m` - if [ "${osarch}" = i686 ] ; then - linux_arch=i586 - elif [ "${osarch}" = x86_64 ] ; then - linux_arch=amd64 - fi - - # Add basic paths - path4sdk=/usr/bin:/bin:/usr/sbin:/sbin - - # Get the previous JDK to be used to bootstrap the build - path4sdk=${bootdir}/bin:${path4sdk} - - # Ant - ANT_HOME=${slashjava}/devtools/share/ant/1.7.0 - export ANT_HOME - antbindir=${ANT_HOME}/bin - fileMustExist "${antbindir}/ant" ant - path4sdk=${antbindir}:${path4sdk} - - # Find GNU make - make=/usr/bin/make - fileMustExist "${make}" make - - umask 002 - -else - - # Windows: Differs on CYGWIN vs. MKS - # Also, blanks in pathnames gives GNU make headaches, so anything placed - # in any ALT_* variable should be the short windows dosname. - - # WINDOWS: Install and use MKS or CYGWIN (should have already been done) - # Assumption here is that you are in a shell window via MKS or cygwin. - # MKS install should have defined the environment variable ROOTDIR. - # We also need to figure out which one we have: X86, AMD64 - if [ "`echo ${PROCESSOR_IDENTIFIER} | fgrep AMD64`" != "" ] ; then - windows_arch=amd64 - else - windows_arch=i586 - fi - - # We need to determine if we are running a CYGWIN shell or an MKS shell - # (if uname isn't available, then it will be unix_toolset=unknown) - unix_toolset=unknown - if [ "`uname -a | fgrep Cygwin`" = "" -a -d "${ROOTDIR}" ] ; then - # We kind of assume ROOTDIR is where MKS is and it's ok - unix_toolset=MKS - mkshome=`dosname -s "${ROOTDIR}"` - # Utility to convert to short pathnames without spaces - dosname="${mkshome}/mksnt/dosname -s" - # Most unix utilities are in the mksnt directory of ROOTDIR - unixcommand_path="${mkshome}/mksnt" - path4sdk="${unixcommand_path}" - dirMustExist "${unixcommand_path}" ALT_UNIXCOMMAND_PATH - devtools_path="${slashjava}/devtools/win32/bin" - path4sdk="${devtools_path};${path4sdk}" - # Normally this need not be set, but on Windows it's default is C:/UTILS - ALT_DEVTOOLS_PATH="${devtools_path}" - export ALT_DEVTOOLS_PATH - dirMustExist "${devtools_path}" ALT_DEVTOOLS_PATH - # Find GNU make - make="${devtools_path}/gnumake.exe" - fileMustExist "${make}" make - elif [ "`uname -a | fgrep Cygwin`" != "" -a -f /bin/cygpath ] ; then - # For CYGWIN, uname will have "Cygwin" in it, and /bin/cygpath should exist - unix_toolset=CYGWIN - # Utility to convert to short pathnames without spaces - dosname="/usr/bin/cygpath -a -m -s" - # Most unix utilities are in the /usr/bin - unixcommand_path="/usr/bin" - path4sdk="${unixcommand_path}" - dirMustExist "${unixcommand_path}" ALT_UNIXCOMMAND_PATH - # Find GNU make - make="${unixcommand_path}/make.exe" - fileMustExist "${make}" make - else - echo "WARNING: Cannot figure out if this is MKS or CYGWIN" - fi - - # WINDOWS: Get the previous JDK to be used to bootstrap the build - path4sdk="${bootdir}/bin;${path4sdk}" - - # Ant - ANT_HOME=${slashjava}/devtools/share/ant/1.7.0 - export ANT_HOME - antbindir=${ANT_HOME}/bin - fileMustExist "${antbindir}/ant" ant - path4sdk="${antbindir};${path4sdk}" - - # Turn all \\ into /, remove duplicates and trailing / - slash_path="`echo ${path4sdk} | sed -e 's@\\\\@/@g' -e 's@//@/@g' -e 's@/$@@' -e 's@/;@;@g'`" - - # For windows, it's hard to know where the system is, so we just add this - # to PATH. - path4sdk="${slash_path};${PATH}" - - # Convert path4sdk to cygwin style - if [ "${unix_toolset}" = CYGWIN ] ; then - path4sdk="`/usr/bin/cygpath -p ${path4sdk}`" - fi - -fi - -# Export PATH setting -PATH="${path4sdk}" -export PATH - -# Things we need to unset -unset LD_LIBRARY_PATH -unset LD_LIBRARY_PATH_32 -unset LD_LIBRARY_PATH_64 -unset JAVA_HOME - From 2ce9a96c0120c46a85b281d4cf92f002cc2aad2f Mon Sep 17 00:00:00 2001 From: Kelly O'Hair Date: Thu, 26 Mar 2009 16:52:00 -0700 Subject: [PATCH 48/75] 6822374: Windows: detect X64 when PROCESSOR_IDENTIFIER contains EM64T or Intel64 6822913: Consolidate make/jprt.config files, let JPRT manage this file make it optional in repos Reviewed-by: tbell --- jdk/make/common/shared/Platform.gmk | 18 +- jdk/make/jdk_generic_profile.sh | 3 +- jdk/make/jprt.config | 363 ---------------------------- 3 files changed, 16 insertions(+), 368 deletions(-) delete mode 100644 jdk/make/jprt.config diff --git a/jdk/make/common/shared/Platform.gmk b/jdk/make/common/shared/Platform.gmk index d343cdea1c3..e07de2499fb 100644 --- a/jdk/make/common/shared/Platform.gmk +++ b/jdk/make/common/shared/Platform.gmk @@ -229,11 +229,19 @@ ifeq ($(PLATFORM), windows) TEMP_DISK=C:/temp # GNU Make or MKS overrides $(PROCESSOR_ARCHITECTURE) to always # return "x86". Use the first word of $(PROCESSOR_IDENTIFIER) instead. + PROC_ARCH:=$(word 1, $(PROCESSOR_IDENTIFIER)) + PROC_ARCH:=$(subst x86,X86,$(PROC_ARCH)) + PROC_ARCH:=$(subst Intel64,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst em64t,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst EM64T,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst amd64,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst AMD64,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst ia64,IA64,$(PROC_ARCH)) ifndef ARCH_DATA_MODEL - ifeq ($(word 1, $(PROCESSOR_IDENTIFIER)),ia64) + ifeq ($(PROC_ARCH),IA64) ARCH_DATA_MODEL=64 else - ifeq ($(word 1, $(PROCESSOR_IDENTIFIER)),AMD64) + ifeq ($(PROC_ARCH),X64) ARCH_DATA_MODEL=64 else ARCH_DATA_MODEL=32 @@ -245,10 +253,12 @@ ifeq ($(PLATFORM), windows) # If the user wants to perform a cross compile build then they must # - set ARCH_DATA_MODEL=64 and either # + set ARCH to ia64 or amd64, or - ifeq ($(word 1, $(PROCESSOR_IDENTIFIER)), AMD64) + ifeq ($(PROC_ARCH),X64) ARCH=amd64 else - ARCH=ia64 + ifeq ($(PROC_ARCH),IA64) + ARCH=ia64 + endif endif LIBARCH=$(ARCH) # Value of Java os.arch property diff --git a/jdk/make/jdk_generic_profile.sh b/jdk/make/jdk_generic_profile.sh index 32dd86197ef..125198301ca 100644 --- a/jdk/make/jdk_generic_profile.sh +++ b/jdk/make/jdk_generic_profile.sh @@ -174,7 +174,8 @@ else # Check CYGWIN (should have already been done) # Assumption here is that you are in a shell window via cygwin. - if [ "$(echo ${PROCESSOR_IDENTIFIER} | fgrep AMD64)" != "" ] ; then + proc_arch=`echo "$(PROCESSOR_IDENTIFIER)" | expand | cut -d' ' -f1 | sed -e 's@x86@X86@g' -e 's@Intel64@X64@g' -e 's@em64t@X64@g' -e 's@EM64T@X64@g' -e 's@amd64@X64@g' -e 's@AMD64@X64@g' -e 's@ia64@IA64@g'` + if [ "${proc_arch}" = "X64" ] ; then windows_arch=amd64 else windows_arch=i586 diff --git a/jdk/make/jprt.config b/jdk/make/jprt.config deleted file mode 100644 index d720475cecd..00000000000 --- a/jdk/make/jprt.config +++ /dev/null @@ -1,363 +0,0 @@ -#!echo "This is not a shell script" -############################################################################# -# -# Copyright 2006-2008 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. Sun designates this -# particular file as subject to the "Classpath" exception as provided -# by Sun in the LICENSE file that accompanied this code. -# -# 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. -# -############################################################################# -# -# JPRT shell configuration for building. -# -# Input environment variables: -# ALT_BOOTDIR -# ALT_SLASH_JAVA -# ALT_JDK_IMPORT_PATH -# OPENJDK -# Windows Only: -# PATH -# VS71COMNTOOLS -# PROCESSOR_IDENTIFIER -# ROOTDIR -# -# Output variable settings: -# make Full path to GNU make -# compiler_path Path to compiler bin directory -# compiler_name Unique name of this compiler -# -# Output environment variables: -# PATH -# ALT_COMPILER_PATH -# OPENJDK only: -# ALT_CLOSED_JDK_IMPORT_PATH -# ALT_JDK_DEVTOOLS_DIR -# Windows Only: -# ALT_MSDEVTOOLS_PATH -# ALT_DEVTOOLS_PATH (To avoid the C:/UTILS default) -# LIB -# INCLUDE -# -# After JDK6, most settings will be found via ALT_SLASH_JAVA or -# by way of other system environment variables. If this was JDK5 -# or an older JDK, you might need to export more ALT_* variables. -# -# On Windows AMD64, if MSSDK is not set, assumes Platform SDK is installed at: -# C:/Program Files/Microsoft Platform SDK -# -############################################################################# - -############################################################################# -# Error -error() # message -{ - echo "ERROR: $1" - exit 6 -} -# Directory must exist -dirMustExist() # dir name -{ - if [ ! -d "$1" ] ; then - error "Directory for $2 does not exist: $1" - fi -} -# File must exist -fileMustExist() # dir name -{ - if [ ! -f "$1" ] ; then - error "File for $2 does not exist: $1" - fi -} -############################################################################# - -# Should be set by JPRT as the 3 basic inputs -bootdir="${ALT_BOOTDIR}" -slashjava="${ALT_SLASH_JAVA}" -jdk_import="${ALT_JDK_IMPORT_PATH}" - -# The /java/devtools items -jdk_devtools="${slashjava}/devtools" -share="${jdk_devtools}/share" - -# Needed for langtools, maybe other parts of the build -ANT_HOME="${share}/ant/latest" -export ANT_HOME - -# The 3 bin directories in common to all platforms -sharebin="${share}/bin" -antbin="${ANT_HOME}/bin" - -# Check input -dirMustExist "${bootdir}" ALT_BOOTDIR -dirMustExist "${slashjava}" ALT_SLASH_JAVA -dirMustExist "${jdk_import}" ALT_JDK_IMPORT_PATH -dirMustExist "${ANT_HOME}" ANT_HOME - -# Use the JDK import for now (FIXME: use the binary plugs?) -if [ "${OPENJDK}" = true ] ; then - ALT_CLOSED_JDK_IMPORT_PATH="${jdk_import}" - export ALT_CLOSED_JDK_IMPORT_PATH -fi - -# Uses 'uname -s', but only expect SunOS or Linux, assume Windows otherwise. -osname=`uname -s` -if [ "${osname}" = SunOS ] ; then - - # SOLARIS: Sparc or X86 - osarch=`uname -p` - if [ "${osarch}" = sparc ] ; then - solaris_arch=sparc - else - solaris_arch=i386 - fi - - # Get the compilers into path (make sure it matches ALT setting) - if [ "${JPRT_SOLARIS_COMPILER_NAME}" != "" ] ; then - compiler_name=${JPRT_SOLARIS_COMPILER_NAME} - else - compiler_name=SS12 - fi - compiler_path=${jdk_devtools}/${solaris_arch}/SUNWspro/${compiler_name}/bin - ALT_COMPILER_PATH="${compiler_path}" - export ALT_COMPILER_PATH - dirMustExist "${compiler_path}" ALT_COMPILER_PATH - path4sdk=${compiler_path}:${sharebin}:${antbin} - - # Add basic solaris system paths - path4sdk=${path4sdk}:/usr/ccs/bin:/usr/ccs/lib:/usr/bin:/bin:/usr/sfw/bin - - # Get the previous JDK to be used to bootstrap the build - path4sdk=${bootdir}/bin:${path4sdk} - - # Find GNU make - make=/usr/sfw/bin/gmake - if [ ! -f ${make} ] ; then - make=/opt/sfw/bin/gmake - if [ ! -f ${make} ] ; then - make=${jdk_devtools}/${solaris_arch}/bin/gnumake - fi - fi - fileMustExist "${make}" make - - # File creation mask - umask 002 - -elif [ "${osname}" = Linux ] ; then - - # LINUX: X86, AMD64 - osarch=`uname -m` - if [ "${osarch}" = i686 ] ; then - linux_arch=i586 - elif [ "${osarch}" = x86_64 ] ; then - linux_arch=amd64 - fi - - # Get the compilers into path (make sure it matches ALT setting) - compiler_path=/usr/bin - compiler_name=usr_bin - ALT_COMPILER_PATH="${compiler_path}" - export ALT_COMPILER_PATH - dirMustExist "${compiler_path}" ALT_COMPILER_PATH - path4sdk=${compiler_path}:${sharebin}:${antbin} - - # Add basic paths - path4sdk=${path4sdk}:/usr/bin:/bin:/usr/sbin:/sbin - - # Get the previous JDK to be used to bootstrap the build - path4sdk=${bootdir}/bin:${path4sdk} - - # Find GNU make - make=/usr/bin/make - fileMustExist "${make}" make - - umask 002 - - # Linux platform may be old, use motif files from the devtools area - if [ "${OPENJDK}" = true ] ; then - ALT_JDK_DEVTOOLS_DIR="${jdk_devtools}" - export ALT_JDK_DEVTOOLS_DIR - fi - - -else - - # Windows: Differs on CYGWIN vs. MKS, and the compiler available. - # Also, blanks in pathnames gives GNU make headaches, so anything placed - # in any ALT_* variable should be the short windows dosname. - - # WINDOWS: Install and use MKS or CYGWIN (should have already been done) - # Assumption here is that you are in a shell window via MKS or cygwin. - # MKS install should have defined the environment variable ROOTDIR. - # We also need to figure out which one we have: X86, AMD64 - if [ "`echo ${PROCESSOR_IDENTIFIER} | fgrep AMD64`" != "" ] ; then - windows_arch=amd64 - else - windows_arch=i586 - fi - - # We need to determine if we are running a CYGWIN shell or an MKS shell - # (if uname isn't available, then it will be unix_toolset=unknown) - unix_toolset=unknown - if [ "`uname -a | fgrep Cygwin`" = "" -a -d "${ROOTDIR}" ] ; then - # We kind of assume ROOTDIR is where MKS is and it's ok - unix_toolset=MKS - mkshome=`dosname -s "${ROOTDIR}"` - # Utility to convert to short pathnames without spaces - dosname="${mkshome}/mksnt/dosname -s" - # Most unix utilities are in the mksnt directory of ROOTDIR - unixcommand_path="${mkshome}/mksnt" - path4sdk="${sharebin};${antbin};${unixcommand_path}" - dirMustExist "${unixcommand_path}" ALT_UNIXCOMMAND_PATH - devtools_path="${jdk_devtools}/win32/bin" - path4sdk="${devtools_path};${path4sdk}" - # Normally this need not be set, but on Windows it's default is C:/UTILS - ALT_DEVTOOLS_PATH="${devtools_path}" - export ALT_DEVTOOLS_PATH - dirMustExist "${devtools_path}" ALT_DEVTOOLS_PATH - # Find GNU make - make="${devtools_path}/gnumake.exe" - fileMustExist "${make}" make - elif [ "`uname -a | fgrep Cygwin`" != "" -a -f /bin/cygpath ] ; then - # For CYGWIN, uname will have "Cygwin" in it, and /bin/cygpath should exist - unix_toolset=CYGWIN - # Utility to convert to short pathnames without spaces - dosname="/usr/bin/cygpath -a -m -s" - # Most unix utilities are in the /usr/bin - unixcommand_path="/usr/bin" - path4sdk="${sharebin};${antbin};${unixcommand_path}" - dirMustExist "${unixcommand_path}" ALT_UNIXCOMMAND_PATH - # Find GNU make - make="${unixcommand_path}/make.exe" - fileMustExist "${make}" make - else - echo "WARNING: Cannot figure out if this is MKS or CYGWIN" - fi - - # WINDOWS: Compiler setup (nasty part) - # NOTE: You can use vcvars32.bat to set PATH, LIB, and INCLUDE. - # NOTE: CYGWIN has a link.exe too, make sure the compilers are first - if [ "${windows_arch}" = i586 ] ; then - # 32bit Windows compiler settings - # VisualStudio .NET 2003 VC++ 7.1 (VS71COMNTOOLS should be defined) - vs_root=`${dosname} "${VS71COMNTOOLS}/../.."` - # Fill in PATH, LIB, and INCLUDE (unset all others to make sure) - msdev_root="${vs_root}/Common7/Tools" - msdevtools_path="${msdev_root}/bin" - vc7_root="${vs_root}/Vc7" - compiler_path="${vc7_root}/bin" - compiler_name=VS2003 - platform_sdk="${vc7_root}/PlatformSDK" - # LIB and INCLUDE must use ; as a separator - include4sdk="${vc7_root}/atlmfc/include" - include4sdk="${include4sdk};${vc7_root}/include" - include4sdk="${include4sdk};${platform_sdk}/include/prerelease" - include4sdk="${include4sdk};${platform_sdk}/include" - include4sdk="${include4sdk};${vs_root}/SDK/v1.1/include" - lib4sdk="${vc7_root}/atlmfc/lib" - lib4sdk="${lib4sdk};${vc7_root}/lib" - lib4sdk="${lib4sdk};${platform_sdk}/lib/prerelease" - lib4sdk="${lib4sdk};${platform_sdk}/lib" - lib4sdk="${lib4sdk};${vs_root}/SDK/v1.1/lib" - # Search path and DLL locating path - # WARNING: CYGWIN has a link.exe too, make sure compilers are first - path4sdk="${vs_root}/Common7/Tools/bin;${path4sdk}" - path4sdk="${vs_root}/SDK/v1.1/bin;${path4sdk}" - path4sdk="${vs_root}/Common7/Tools;${path4sdk}" - path4sdk="${vs_root}/Common7/Tools/bin/prerelease;${path4sdk}" - path4sdk="${vs_root}/Common7/IDE;${path4sdk}" - path4sdk="${compiler_path};${path4sdk}" - elif [ "${windows_arch}" = amd64 ] ; then - # AMD64 64bit Windows compiler settings - if [ "${MSSDK}" != "" ] ; then - platform_sdk="${MSSDK}" - else - platform_sdk=`${dosname} "C:/Program Files/Microsoft Platform SDK/"` - fi - compiler_path="${platform_sdk}/Bin/win64/x86/AMD64" - compiler_name=VS2005_PSDK - msdevtools_path="${platform_sdk}/Bin" - # LIB and INCLUDE must use ; as a separator - include4sdk="${platform_sdk}/Include" - include4sdk="${include4sdk};${platform_sdk}/Include/crt/sys" - include4sdk="${include4sdk};${platform_sdk}/Include/mfc" - include4sdk="${include4sdk};${platform_sdk}/Include/atl" - include4sdk="${include4sdk};${platform_sdk}/Include/crt" - lib4sdk="${platform_sdk}/Lib/AMD64" - lib4sdk="${lib4sdk};${platform_sdk}/Lib/AMD64/atlmfc" - # Search path and DLL locating path - # WARNING: CYGWIN has a link.exe too, make sure compilers are first - path4sdk="${platform_sdk}/bin;${path4sdk}" - path4sdk="${compiler_path};${path4sdk}" - fi - # Export LIB and INCLUDE - unset lib - unset Lib - LIB="${lib4sdk}" - export LIB - unset include - unset Include - INCLUDE="${include4sdk}" - export INCLUDE - # Set the ALT variable - ALT_COMPILER_PATH=`${dosname} "${compiler_path}"` - export ALT_COMPILER_PATH - dirMustExist "${compiler_path}" ALT_COMPILER_PATH - ALT_MSDEVTOOLS_PATH=`${dosname} "${msdevtools_path}"` - export ALT_MSDEVTOOLS_PATH - dirMustExist "${msdevtools_path}" ALT_MSDEVTOOLS_PATH - - # WINDOWS: Get the previous JDK to be used to bootstrap the build - path4sdk="${bootdir}/bin;${path4sdk}" - - # Turn all \\ into /, remove duplicates and trailing / - slash_path="`echo ${path4sdk} | sed -e 's@\\\\@/@g' -e 's@//@/@g' -e 's@/$@@' -e 's@/;@;@g'`" - - # For windows, it's hard to know where the system is, so we just add this - # to PATH. - path4sdk="${slash_path};${PATH}" - - # Convert path4sdk to cygwin style - if [ "${unix_toolset}" = CYGWIN ] ; then - path4sdk="`/usr/bin/cygpath -p ${path4sdk}`" - fi - - # Set special windows ALT variables - ALT_ISHIELDDIR="C:/ishield802" - export ALT_ISHIELDDIR - - # Sponsors binaries - ALT_SPONSOR1DIR=C:/sponsor_binaries - export ALT_SPONSOR1DIR - ALT_SPONSOR2DIR=C:/sponsor_binaries - export ALT_SPONSOR2DIR - -fi - -# Export PATH setting -PATH="${path4sdk}" -export PATH - -# Things we need to unset -unset LD_LIBRARY_PATH -unset LD_LIBRARY_PATH_32 -unset LD_LIBRARY_PATH_64 -unset JAVA_HOME - From 9bac626c1a054c6921093bd2b275a6f6b8d2b3a0 Mon Sep 17 00:00:00 2001 From: Xiomara Jayasena Date: Fri, 27 Mar 2009 14:11:31 -0700 Subject: [PATCH 49/75] Added tag jdk7-b52 for changeset 90eb5f83241a --- .hgtags-top-repo | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags-top-repo b/.hgtags-top-repo index 52f1f706812..5ac8ad95712 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -26,3 +26,4 @@ d7744e86dedc21a8ecf6bdb73eb191b8eaf5b0da jdk7-b47 aee93a8992d2389121eb610c00a86196f3e2b9b0 jdk7-b49 5111e13e44e542fe945b47ab154546daec36737d jdk7-b50 0f0189d55ce4a1f7840da7582ac7d970b3b7ab15 jdk7-b51 +4264c2fe66493e57c411045a1b61377796641e45 jdk7-b52 From a83e0c09252de5635a1a60eea3e44414758597c8 Mon Sep 17 00:00:00 2001 From: Xiomara Jayasena Date: Fri, 27 Mar 2009 14:11:32 -0700 Subject: [PATCH 50/75] Added tag jdk7-b52 for changeset 8608524e334e --- corba/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/corba/.hgtags b/corba/.hgtags index 28a93dc8343..91ac5a1ccae 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -26,3 +26,4 @@ ccd6a16502e0650d91d85c4b86be05cbcd461a87 jdk7-b42 d70978bc64bc7a04be7797ab0dcd9b7b1b3a6bff jdk7-b49 0edbd0074b02b42b2b83cc47cb391d4869b7a8ec jdk7-b50 3eb8f1047a7402a9a79937d1c39560e931e91da2 jdk7-b51 +bec82237d694f9802b820fa11bbb4f7fa9bf8e77 jdk7-b52 From 422ea850e0a4475c8fdf86a44a125e7ade494527 Mon Sep 17 00:00:00 2001 From: Xiomara Jayasena Date: Fri, 27 Mar 2009 14:11:35 -0700 Subject: [PATCH 51/75] Added tag jdk7-b52 for changeset 0d989c04422c --- hotspot/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 21dac82c44e..475bfa37988 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -26,3 +26,4 @@ bcb33806d186561c781992e5f4d8a90bb033f9f0 jdk7-b48 8b22ccb5aba2c6c11bddf6488a7bb7ef5b4bf2be jdk7-b49 dae503d9f04c1a11e182dbf7f770509c28dc0609 jdk7-b50 2581d90c6c9b2012da930eb4742add94a03069a0 jdk7-b51 +1b1e8f1a4fe8cebc01c022484f78148e17b62a0d jdk7-b52 From 93a90129b2ad174a8d6adb641eb786fc98814c8f Mon Sep 17 00:00:00 2001 From: Xiomara Jayasena Date: Fri, 27 Mar 2009 14:11:39 -0700 Subject: [PATCH 52/75] Added tag jdk7-b52 for changeset 37c56ec4ec7d --- jaxp/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxp/.hgtags b/jaxp/.hgtags index b479a50ab7b..8951b3d1ac5 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -26,3 +26,4 @@ d711ad1954b294957737ea386cfd4d3c05028a36 jdk7-b47 5c1f24531903573c1830775432276da567243f9c jdk7-b49 e8514e2be76d90889ebdb90d627aca2db5c150c6 jdk7-b50 ae890d80d5dffcd4dc77a1f17d768e192d1852c7 jdk7-b51 +69ad87dc25cbcaaaded4727199395ad0c78bc427 jdk7-b52 From d8cd1fc4329a3561f63b4b971e649b769111d6d5 Mon Sep 17 00:00:00 2001 From: Xiomara Jayasena Date: Fri, 27 Mar 2009 14:11:40 -0700 Subject: [PATCH 53/75] Added tag jdk7-b52 for changeset 56b454d324bb --- jaxws/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxws/.hgtags b/jaxws/.hgtags index 2869a6be543..62bf7fdbd4d 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -26,3 +26,4 @@ af4a3eeb7812a5d09a241c50b51b3c648a9d45c1 jdk7-b46 18ca864890f3d4ed942ecbffb78c936a57759921 jdk7-b49 5be52db581f1ea91ab6e0eb34ba7f439125bfb16 jdk7-b50 41a66a42791ba90bff489af72cbfea71be9b40a5 jdk7-b51 +e646890d18b770f625f14ed4ad5c50554d8d3d8b jdk7-b52 From ace77b0dc3f00908ba37a8bd89c43d1f28f42ec1 Mon Sep 17 00:00:00 2001 From: Xiomara Jayasena Date: Fri, 27 Mar 2009 14:11:45 -0700 Subject: [PATCH 54/75] Added tag jdk7-b52 for changeset ea5331b4a192 --- jdk/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/.hgtags b/jdk/.hgtags index 4790ae52876..39ec72bb7a9 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -26,3 +26,4 @@ b4ac413b1f129eeef0acab3f31081c1b7dfe3b27 jdk7-b47 8311105ea7a3db7bcbcb2b696459127c7f2297a4 jdk7-b49 58ba2cd5a25053684ec53205d95edeeaa0006f13 jdk7-b50 fea0898259ae41c73620b1815aa48f036216155c jdk7-b51 +bcbeadb4a5d759b29e876ee2c83401e91ff22f60 jdk7-b52 From 0f23916d8bb90249cf5e7313abb731e47c67b2b6 Mon Sep 17 00:00:00 2001 From: Xiomara Jayasena Date: Fri, 27 Mar 2009 14:11:53 -0700 Subject: [PATCH 55/75] Added tag jdk7-b52 for changeset a9071341dbea --- langtools/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/langtools/.hgtags b/langtools/.hgtags index a260d94e956..0ea2c411d86 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -26,3 +26,4 @@ c53007f34195f69223bdd4125ec6c0740f7d6736 jdk7-b48 d17d927ad9bdfafae32451645d182acb7bed7be6 jdk7-b49 46f2f6ed96f13fc49fec3d1b6aa616686128cb57 jdk7-b50 8c55d5b0ed71ed3a749eb97e4eab79b4831649b8 jdk7-b51 +29329051d483d39f66073752ba4afbf29d893cfe jdk7-b52 From 0a7ba6e27e3fd51a1a63c8a6692cedd03dda45f0 Mon Sep 17 00:00:00 2001 From: Tim Bell Date: Tue, 31 Mar 2009 15:27:40 -0700 Subject: [PATCH 56/75] 6819847: build is broken for OpenJDK with plugs Reviewed-by: jjg, robilad, ohair --- jdk/make/Makefile | 5 ----- jdk/make/common/Defs.gmk | 9 +++++++++ jdk/make/common/shared/Sanity-Settings.gmk | 1 + jdk/make/java/redist/Makefile | 6 ++++-- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/jdk/make/Makefile b/jdk/make/Makefile index c78e4c27e01..27781781f62 100644 --- a/jdk/make/Makefile +++ b/jdk/make/Makefile @@ -328,11 +328,6 @@ else $(ECHO) "Rule $@ does not apply on $(PLATFORM)-$(ARCH)" endif -# -# Binary Plug rules and macros -# -include $(BUILDDIR)/common/internal/BinaryPlugs.gmk - # # Get top level sccs_get rule # diff --git a/jdk/make/common/Defs.gmk b/jdk/make/common/Defs.gmk index 33eedad16a4..d959123fdae 100644 --- a/jdk/make/common/Defs.gmk +++ b/jdk/make/common/Defs.gmk @@ -145,6 +145,11 @@ endif # 2. ALT_BINARY_PLUGS_PATH overrides all locations of classes and libraries # 3. ALT_BUILD_BINARY_PLUGS_PATH is used to find a ALT_BINARY_PLUGS_PATH # 4. ALT_CLOSED_JDK_IMPORT_PATH is used to locate classes and libraries +# Note: If any of the ALT_ variables are modified here, it is assumed +# that the build should be done with IMPORT_BINARY_PLUGS=true as +# well. Otherwise the default will be IMPORT_BINARY_PLUGS=false. +# Lastly, setting IMPORT_BINARY_PLUGS=false on the command line +# will override this logic, and plugs will not be imported. # # Always needed, defines the name of the imported/exported jarfile @@ -155,9 +160,11 @@ ifdef OPENJDK CLOSED_JDK_IMPORT_PATH = $(ALT_CLOSED_JDK_IMPORT_PATH) BINARY_PLUGS_PATH = $(CLOSED_JDK_IMPORT_PATH) BINARY_PLUGS_JARFILE = $(CLOSED_JDK_IMPORT_PATH)/jre/lib/rt.jar + IMPORT_BINARY_PLUGS=true endif ifdef ALT_BUILD_BINARY_PLUGS_PATH BUILD_BINARY_PLUGS_PATH = $(ALT_BUILD_BINARY_PLUGS_PATH) + IMPORT_BINARY_PLUGS=true else BUILD_BINARY_PLUGS_PATH = $(SLASH_JAVA)/re/jdk/$(JDK_VERSION)/promoted/latest/openjdk/binaryplugs endif @@ -166,9 +173,11 @@ ifdef OPENJDK ifdef ALT_BINARY_PLUGS_PATH BINARY_PLUGS_PATH = $(ALT_BINARY_PLUGS_PATH) BINARY_PLUGS_JARFILE = $(BINARY_PLUGS_PATH)/jre/lib/$(BINARY_PLUGS_JARNAME) + IMPORT_BINARY_PLUGS=true endif ifdef ALT_BINARY_PLUGS_JARFILE BINARY_PLUGS_JARFILE = $(ALT_BINARY_PLUGS_JARFILE) + IMPORT_BINARY_PLUGS=true endif endif # OPENJDK diff --git a/jdk/make/common/shared/Sanity-Settings.gmk b/jdk/make/common/shared/Sanity-Settings.gmk index 987ba93489a..b64e3b52a13 100644 --- a/jdk/make/common/shared/Sanity-Settings.gmk +++ b/jdk/make/common/shared/Sanity-Settings.gmk @@ -245,6 +245,7 @@ ifdef OPENJDK ALL_SETTINGS+=$(call addAltSetting,FREETYPE_HEADERS_PATH) ALL_SETTINGS+=$(call addAltSetting,FREETYPE_LIB_PATH) ALL_SETTINGS+=$(call addHeading,OPENJDK Import Binary Plug Settings) + ALL_SETTINGS+=$(call addOptionalSetting,IMPORT_BINARY_PLUGS) ALL_SETTINGS+=$(call addAltSetting,BINARY_PLUGS_JARFILE) ALL_SETTINGS+=$(call addAltSetting,BINARY_PLUGS_PATH) ALL_SETTINGS+=$(call addAltSetting,BUILD_BINARY_PLUGS_PATH) diff --git a/jdk/make/java/redist/Makefile b/jdk/make/java/redist/Makefile index 159c247b3f3..9ab884dd247 100644 --- a/jdk/make/java/redist/Makefile +++ b/jdk/make/java/redist/Makefile @@ -251,9 +251,11 @@ endif # INCLUDE_SA # ifdef OPENJDK -include $(BUILDDIR)/common/internal/BinaryPlugs.gmk + ifeq ($(IMPORT_BINARY_PLUGS),true) + include $(BUILDDIR)/common/internal/BinaryPlugs.gmk -build: import-binary-plugs + build: import-binary-plugs + endif else # !OPENJDK From 183aabe3b52aa416e2f1c02c4a3fdde6785c64e1 Mon Sep 17 00:00:00 2001 From: Kelly O'Hair Date: Tue, 31 Mar 2009 16:10:31 -0700 Subject: [PATCH 57/75] 6604458: linux_x64-fastdebug-c2 fails on hyperbolic trig tests Reviewed-by: tbell --- jdk/make/common/Defs-linux.gmk | 7 +++++-- jdk/make/common/Defs-solaris.gmk | 7 +++++-- jdk/make/common/Defs-windows.gmk | 3 +++ jdk/make/java/fdlibm/Makefile | 2 ++ 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/jdk/make/common/Defs-linux.gmk b/jdk/make/common/Defs-linux.gmk index 9ecdd4d7156..591b6ccae31 100644 --- a/jdk/make/common/Defs-linux.gmk +++ b/jdk/make/common/Defs-linux.gmk @@ -94,6 +94,9 @@ ifndef OPTIMIZATION_LEVEL OPTIMIZATION_LEVEL = LOWER endif endif +ifndef FASTDEBUG_OPTIMIZATION_LEVEL + FASTDEBUG_OPTIMIZATION_LEVEL = LOWER +endif CC_OPT/NONE = CC_OPT/LOWER = -O2 @@ -173,8 +176,8 @@ CXXFLAGS_COMMON += $(CFLAGS_REQUIRED) # FASTDEBUG: Optimize the code in the -g versions, gives us a faster debug java ifeq ($(FASTDEBUG), true) - CFLAGS_DBG += $(CC_OPT/LOWER) - CXXFLAGS_DBG += $(CC_OPT/LOWER) + CFLAGS_DBG += $(CC_OPT/$(FASTDEBUG_OPTIMIZATION_LEVEL)) + CXXFLAGS_DBG += $(CC_OPT/$(FASTDEBUG_OPTIMIZATION_LEVEL)) endif CPPFLAGS_COMMON = -D$(ARCH) -DARCH='"$(ARCH)"' -DLINUX $(VERSION_DEFINES) \ diff --git a/jdk/make/common/Defs-solaris.gmk b/jdk/make/common/Defs-solaris.gmk index 9b5cc8b721b..5b1d237caae 100644 --- a/jdk/make/common/Defs-solaris.gmk +++ b/jdk/make/common/Defs-solaris.gmk @@ -93,6 +93,9 @@ ifndef OPTIMIZATION_LEVEL OPTIMIZATION_LEVEL = LOWER endif endif +ifndef FASTDEBUG_OPTIMIZATION_LEVEL + FASTDEBUG_OPTIMIZATION_LEVEL = LOWER +endif # # If -Xa is in CFLAGS_COMMON it will end up ahead of $(CC_OPT) for the @@ -143,8 +146,8 @@ endif # Performance/size of files should be about the same, maybe smaller. # ifeq ($(FASTDEBUG), true) - CFLAGS_DEBUG_OPTION = -g $(CC_OPT/LOWER) - CXXFLAGS_DEBUG_OPTION = -g0 $(CXX_OPT/LOWER) + CFLAGS_DEBUG_OPTION = -g $(CC_OPT/$(FASTDEBUG_OPTIMIZATION_LEVEL)) + CXXFLAGS_DEBUG_OPTION = -g0 $(CXX_OPT/$(FASTDEBUG_OPTIMIZATION_LEVEL)) endif CFLAGS_COMMON = -L$(OBJDIR) diff --git a/jdk/make/common/Defs-windows.gmk b/jdk/make/common/Defs-windows.gmk index 7cb827928cd..00b8ea71e2a 100644 --- a/jdk/make/common/Defs-windows.gmk +++ b/jdk/make/common/Defs-windows.gmk @@ -111,6 +111,9 @@ ifndef OPTIMIZATION_LEVEL OPTIMIZATION_LEVEL = LOWER endif endif +ifndef FASTDEBUG_OPTIMIZATION_LEVEL + FASTDEBUG_OPTIMIZATION_LEVEL = LOWER +endif ifeq ($(CC_VERSION),msvc) # Visual Studio .NET 2003 or VS2003 compiler option definitions: diff --git a/jdk/make/java/fdlibm/Makefile b/jdk/make/java/fdlibm/Makefile index eeb5e744f41..739eaf4403f 100644 --- a/jdk/make/java/fdlibm/Makefile +++ b/jdk/make/java/fdlibm/Makefile @@ -45,6 +45,7 @@ FDLIBM_SRC = $(SHARE_SRC)/native/java/lang/fdlibm ifeq ($(PLATFORM),windows) # Turn all optimizations off OPTIMIZATION_LEVEL = NONE + FASTDEBUG_OPTIMIZATION_LEVEL = NONE OTHER_CFLAGS = CPPFLAGS_DBG += -DLOGGING endif @@ -56,6 +57,7 @@ endif ifeq ($(PLATFORM),linux) # Turn all optimizations off OPTIMIZATION_LEVEL = NONE + FASTDEBUG_OPTIMIZATION_LEVEL = NONE endif # From a4fccad415c0293f1b3219c53edd3848556fc14b Mon Sep 17 00:00:00 2001 From: Kelly O'Hair Date: Tue, 31 Mar 2009 16:11:09 -0700 Subject: [PATCH 58/75] 6745361: Add -XX options to prevent stdout/stderr pollution using fastdebug/debug bootjdk Reviewed-by: tbell --- jdk/make/common/shared/Defs-java.gmk | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/jdk/make/common/shared/Defs-java.gmk b/jdk/make/common/shared/Defs-java.gmk index 8454ab2d674..78f87294fbe 100644 --- a/jdk/make/common/shared/Defs-java.gmk +++ b/jdk/make/common/shared/Defs-java.gmk @@ -59,7 +59,15 @@ else ADD_CLIENT_VM_OPTION = true endif endif -JAVA_JVM_FLAGS = + +# Options for hotspot to turn off printing of options with fastdebug version +# and creating the hotspot.log file. +JAVA_HOTSPOT_DISABLE_PRINT_VMOPTIONS = \ + -XX:-PrintVMOptions -XX:+UnlockDiagnosticVMOptions -XX:-LogVMOutput + +# JVM options +JAVA_JVM_FLAGS = $(JAVA_HOTSPOT_DISABLE_PRINT_VMOPTIONS) + ifeq ($(ADD_CLIENT_VM_OPTION), true) JAVA_JVM_FLAGS += -client endif From 53b5f6ae6b5e0a276a706211dad4f2ec3da19358 Mon Sep 17 00:00:00 2001 From: Kelly O'Hair Date: Tue, 31 Mar 2009 16:12:56 -0700 Subject: [PATCH 59/75] 6502548: test/Makefile needs to be setup to allow for JPRT testrules (NSK and JCK testing too?) A work in progress on testing additions for JPRT system. Reviewed-by: tbell --- jdk/test/Makefile | 468 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 403 insertions(+), 65 deletions(-) diff --git a/jdk/test/Makefile b/jdk/test/Makefile index 5435bf0a614..775e7cbc913 100644 --- a/jdk/test/Makefile +++ b/jdk/test/Makefile @@ -1,12 +1,44 @@ # -# Makefile to run jtreg +# Copyright 1995-2008 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. Sun designates this +# particular file as subject to the "Classpath" exception as provided +# by Sun in the LICENSE file that accompanied this code. +# +# 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. +# + +# +# Makefile to run various jdk tests # # Get OS/ARCH specifics OSNAME = $(shell uname -s) + +# Commands to run on paths to make mixed paths for java on windows +GETMIXEDPATH=echo + +# Location of developer shared files +SLASH_JAVA = /java + +# Platform specific settings ifeq ($(OSNAME), SunOS) PLATFORM = solaris - JCT_PLATFORM = solaris ARCH = $(shell uname -p) ifeq ($(ARCH), i386) ARCH=i586 @@ -14,97 +46,403 @@ ifeq ($(OSNAME), SunOS) endif ifeq ($(OSNAME), Linux) PLATFORM = linux - JCT_PLATFORM = linux ARCH = $(shell uname -m) ifeq ($(ARCH), i386) ARCH=i586 endif endif -ifeq ($(OSNAME), Windows_NT) + +# Cannot trust uname output +ifneq ($(PROCESSOR_IDENTIFIER), ) PLATFORM = windows - JCT_PLATFORM = win32 - ifeq ($(word 1, $(PROCESSOR_IDENTIFIER)),ia64) - ARCH=ia64 + SLASH_JAVA = J: + # A variety of ways to say X64 arch :^( + PROC_ARCH:=$(word 1, $(PROCESSOR_IDENTIFIER)) + PROC_ARCH:=$(subst x86,X86,$(PROC_ARCH)) + PROC_ARCH:=$(subst x64,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst AMD64,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst amd64,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst EM64T,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst em64t,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst intel64,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst Intel64,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst INTEL64,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst ia64,IA64,$(PROC_ARCH)) + ifeq ($(PROC_ARCH),IA64) + ARCH = ia64 else - ifeq ($(word 1, $(PROCESSOR_IDENTIFIER)),AMD64) - ARCH=x64 + ifeq ($(PROC_ARCH),X64) + ARCH = x64 else - ifeq ($(word 1, $(PROCESSOR_IDENTIFIER)),EM64T) - ARCH=x64 - else - ARCH=i586 - endif + ARCH = i586 endif endif + EXESUFFIX = .exe + # These need to be different depending on MKS or CYGWIN + ifeq ($(findstring cygdrive,$(shell (cd C:/ && pwd))), ) + GETMIXEDPATH=dosname -s + else + GETMIXEDPATH=cygpath -m -s + endif endif +# Utilities used +CD = cd +CP = cp +ECHO = echo +MKDIR = mkdir +ZIP = zip + # Root of this test area (important to use full paths in some places) TEST_ROOT := $(shell pwd) -# Default bundle of all test results (passed or not) -JPRT_ARCHIVE_BUNDLE=$(TEST_ROOT)/JPRT_ARCHIVE_BUNDLE.zip - -# Default home for JTREG -ifeq ($(PLATFORM), windows) - JT_HOME = J:/svc/jct-tools3.2.2_02 - JTREG_KEY_OPTION=-k:!ignore +# Root of all test results +ifdef ALT_OUTPUTDIR + ABS_OUTPUTDIR = $(ALT_OUTPUTDIR) else - JT_HOME = /java/svc/jct-tools3.2.2_02 - JTREG_KEY_OPTION=-k:\!ignore + ABS_OUTPUTDIR = $(TEST_ROOT)/../build/$(PLATFORM)-$(ARCH) +endif +ABS_BUILD_ROOT = $(ABS_OUTPUTDIR) +ABS_TEST_OUTPUT_DIR := $(ABS_BUILD_ROOT)/testoutput + +# Expect JPRT to set PRODUCT_HOME (the product or jdk in this case to test) +ifndef PRODUCT_HOME + # Try to use j2sdk-image if it exists + ABS_JDK_IMAGE = $(ABS_BUILD_ROOT)/j2sdk-image + PRODUCT_HOME := \ + $(shell \ + if [ -d $(ABS_JDK_IMAGE) ] ; then \ + $(ECHO) "$(ABS_JDK_IMAGE)"; \ + else \ + $(ECHO) "$(ABS_BUILD_ROOT)" ; \ + fi) + PRODUCT_HOME := $(PRODUCT_HOME) endif -# Default JTREG to run -JTREG = $(JT_HOME)/$(JCT_PLATFORM)/bin/jtreg +# Expect JPRT to set JPRT_PRODUCT_ARGS (e.g. -server etc.) +# Should be passed into 'java' only. +ifdef JPRT_PRODUCT_ARGS + JAVA_ARGS = $(JPRT_PRODUCT_ARGS) +endif -# Default JDK to test -JAVA_HOME = $(TEST_ROOT)/../build/$(PLATFORM)-$(ARCH) +# Expect JPRT to set JPRT_PRODUCT_VM_ARGS (e.g. -Xcomp etc.) +# Should be passed into anything running the vm (java, javac, javadoc, ...). +ifdef JPRT_PRODUCT_VM_ARGS + JAVA_VM_ARGS = $(JPRT_PRODUCT_VM_ARGS) +endif -# The test directories to run -DEFAULT_TESTDIRS = demo/jvmti/gctest demo/jvmti/hprof -TESTDIRS = $(DEFAULT_TESTDIRS) +# Expect JPRT to set JPRT_ARCHIVE_BUNDLE (path to zip bundle for results) +ARCHIVE_BUNDLE = $(ABS_TEST_OUTPUT_DIR)/ARCHIVE_BUNDLE.zip +ifdef JPRT_ARCHIVE_BUNDLE + ARCHIVE_BUNDLE = $(JPRT_ARCHIVE_BUNDLE) +endif -# Root of all test results -JTREG_OUTPUT_DIR = $(TEST_ROOT)/o_$(PLATFORM)-$(ARCH) +# How to create the test bundle (pass or fail, we want to create this) +# Follow command with ";$(BUNDLE_UP_AND_EXIT)", so it always gets executed. +ZIP_UP_RESULTS = ( $(MKDIR) -p `dirname $(ARCHIVE_BUNDLE)` \ + && $(CD) $(ABS_TEST_OUTPUT_DIR) \ + && $(ZIP) -q -r $(ARCHIVE_BUNDLE) . ) +BUNDLE_UP_AND_EXIT = ( exitCode=$$? && $(ZIP_UP_RESULTS) && exit $${exitCode} ) -# Export this setting and pass it in. -#JAVA_TOOL_OPTIONS = -Djava.awt.headless=true -#export JAVA_TOOL_OPTIONS +################################################################ -# Default make rule -all: clean check tests $(JPRT_ARCHIVE_BUNDLE) - @echo "Testing completed successfully" +# Default make rule (runs jtreg_tests) +all: jtreg_tests + @$(ECHO) "Testing completed successfully" -# Chaeck to make sure these directories exist -check: $(JT_HOME) $(JAVA_HOME) $(JTREG) - -# Run the tests -tests: FRC - @echo "Using export JAVA_TOOL_OPTIONS=$(JAVA_TOOL_OPTIONS)" - @rm -f -r $(JTREG_OUTPUT_DIR) - @mkdir -p $(JTREG_OUTPUT_DIR) - $(JTREG) -a -v:fail,error \ - $(JTREG_KEY_OPTION) \ - -r:$(JTREG_OUTPUT_DIR)/JTreport \ - -w:$(JTREG_OUTPUT_DIR)/JTwork \ - -jdk:$(JAVA_HOME) \ - $(JAVA_TOOL_OPTIONS:%=-vmoption:%) \ - $(JAVA_ARGS:%=-vmoption:%) \ - $(TESTDIRS) - -# Bundle up the results -$(JPRT_ARCHIVE_BUNDLE): FRC - @rm -f $@ - @mkdir -p $(@D) - ( cd $(JTREG_OUTPUT_DIR) && zip -q -r $@ . ) +# Prep for output +prep: clean + @$(MKDIR) -p $(ABS_TEST_OUTPUT_DIR) + @$(MKDIR) -p `dirname $(ARCHIVE_BUNDLE)` # Cleanup clean: - rm -f -r $(JTREG_OUTPUT_DIR) - rm -f $(JPRT_ARCHIVE_BUNDLE) + $(RM) -r $(ABS_TEST_OUTPUT_DIR) + $(RM) $(ARCHIVE_BUNDLE) -# Used to force a target rules to run -FRC: +################################################################ + +# jtreg tests + +# Expect JT_HOME to be set for jtreg tests. (home for jtreg) +JT_HOME = $(SLASH_JAVA)/re/jtreg/4.0/promoted/latest/binaries/jtreg +ifdef JPRT_JTREG_HOME + JT_HOME = $(JPRT_JTREG_HOME) +endif + +# Expect JPRT to set TESTDIRS to the jtreg test dirs +ifndef TESTDIRS + TESTDIRS = demo/jvmti/gctest demo/jvmti/hprof +endif + +# Default JTREG to run (win32 script works for everybody) +JTREG = $(JT_HOME)/win32/bin/jtreg + +jtreg_tests: prep $(JT_HOME) $(PRODUCT_HOME) $(JTREG) + $(RM) $(JTREG).orig + cp $(JTREG) $(JTREG).orig + $(RM) $(JTREG) + sed -e 's@-J\*@-J-*@' $(JTREG).orig > $(JTREG) + chmod a+x $(JTREG) + ( JT_HOME=$(shell $(GETMIXEDPATH) "$(JT_HOME)"); \ + export JT_HOME; \ + $(shell $(GETMIXEDPATH) "$(JTREG)") \ + -a -v:fail,error \ + -ignore:quiet \ + $(EXTRA_JTREG_OPTIONS) \ + -r:$(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/JTreport \ + -w:$(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/JTwork \ + -jdk:$(shell $(GETMIXEDPATH) "$(PRODUCT_HOME)") \ + $(JAVA_ARGS:%=-javaoptions:%) \ + $(JAVA_VM_ARGS:%=-vmoption:%) \ + $(TESTDIRS) \ + ) ; $(BUNDLE_UP_AND_EXIT) + +PHONY_LIST += jtreg_tests + +################################################################ + +# packtest + +# Expect JPRT to set JPRT_PACKTEST_HOME. +PACKTEST_HOME = /net/jprt-web.sfbay.sun.com/jprt/allproducts/packtest +ifdef JPRT_PACKTEST_HOME + PACKTEST_HOME = $(JPRT_PACKTEST_HOME) +endif + +packtest: prep $(PACKTEST_HOME)/ptest $(PRODUCT_HOME) + ( $(CD) $(PACKTEST_HOME) && \ + $(PACKTEST_HOME)/ptest \ + -t "$(PRODUCT_HOME)" \ + $(PACKTEST_STRESS_OPTION) \ + $(EXTRA_PACKTEST_OPTIONS) \ + -W $(ABS_TEST_OUTPUT_DIR) \ + $(JAVA_ARGS:%=-J %) \ + $(JAVA_VM_ARGS:%=-J %) \ + ) ; $(BUNDLE_UP_AND_EXIT) + +packtest_stress: PACKTEST_STRESS_OPTION=-s +packtest_stress: packtest + +PHONY_LIST += packtest packtest_stress + +################################################################ + +# vmsqe tests + +# Expect JPRT to set JPRT_VMSQE_HOME. +VMSQE_HOME = /java/sqe/comp/vm/testbase/sqe/vm/current/build/latest/vm +ifdef JPRT_VMSQE_HOME + VMSQE_HOME = $(JPRT_VMSQE_HOME) +endif + +# Expect JPRT to set JPRT_RUNVMSQE_HOME. +RUNVMSQE_HOME = /net/jprt-web.sfbay.sun.com/jprt/allproducts/runvmsqe +ifdef JPRT_RUNVMSQE_HOME + RUNVMSQE_HOME = $(JPRT_RUNVMSQE_HOME) +endif + +# Expect JPRT to set JPRT_TONGA3_HOME. +TONGA3_HOME = /java/sqe//tools/gtee/harness/tonga +ifdef JPRT_TONGA3_HOME + TONGA3_HOME = $(JPRT_TONGA3_HOME) +endif + +RUNVMSQE_BIN = $(RUNVMSQE_HOME)/bin/runvmsqe + +vmsqe_tests: prep $(VMSQE_HOME)/vm $(TONGA3_HOME) $(RUNVMSQE_BIN) $(PRODUCT_HOME) + $(RM) -r $(ABS_TEST_OUTPUT_DIR)/vmsqe + ( $(CD) $(ABS_TEST_OUTPUT_DIR) && \ + $(RUNVMSQE_BIN) \ + -jdk "$(PRODUCT_HOME)" \ + -o "$(ABS_TEST_OUTPUT_DIR)/vmsqe" \ + -testbase "$(VMSQE_HOME)/vm" \ + -tonga "$(TONGA3_HOME)" \ + -tongajdk "$(ALT_BOOTDIR)" \ + $(JAVA_ARGS) \ + $(JAVA_VM_ARGS) \ + $(RUNVMSQE_TEST_OPTION) \ + $(EXTRA_RUNVMSQE_OPTIONS) \ + ) ; $(BUNDLE_UP_AND_EXIT) + +vmsqe_jdwp: RUNVMSQE_TEST_OPTION=-jdwp +vmsqe_jdwp: vmsqe_tests + +vmsqe_jdi: RUNVMSQE_TEST_OPTION=-jdi +vmsqe_jdi: vmsqe_tests + +vmsqe_jdb: RUNVMSQE_TEST_OPTION=-jdb +vmsqe_jdb: vmsqe_tests + +vmsqe_quick-jdi: RUNVMSQE_TEST_OPTION=-quick-jdi +vmsqe_quick-jdi: vmsqe_tests + +vmsqe_sajdi: RUNVMSQE_TEST_OPTION=-sajdi +vmsqe_sajdi: vmsqe_tests + +vmsqe_jvmti: RUNVMSQE_TEST_OPTION=-jvmti +vmsqe_jvmti: vmsqe_tests + +vmsqe_hprof: RUNVMSQE_TEST_OPTION=-hprof +vmsqe_hprof: vmsqe_tests + +vmsqe_monitoring: RUNVMSQE_TEST_OPTION=-monitoring +vmsqe_monitoring: vmsqe_tests + +PHONY_LIST += vmsqe_jdwp vmsqe_jdi vmsqe_jdb vmsqe_quick-jdi vmsqe_sajdi \ + vmsqe_jvmti vmsqe_hprof vmsqe_monitoring vmsqe_tests + +################################################################ + +# jck tests + +JCK_WORK_DIR = $(ABS_TEST_OUTPUT_DIR)/JCKwork +JCK_REPORT_DIR = $(ABS_TEST_OUTPUT_DIR)/JCKreport +JCK_PROPERTIES = $(ABS_TEST_OUTPUT_DIR)/jck.properties +JCK_CONFIG = $(ABS_TEST_OUTPUT_DIR)/jck.config + +JCK_JAVA_EXE = $(PRODUCT_HOME)/bin/java$(EXESUFFIX) + +JCK_JAVATEST_JAR = $(JCK_HOME)/lib/javatest.jar +JCK_JAVATEST = $(ALT_BOOTDIR)/bin/java -jar $(JCK_JAVATEST_JAR) + +$(JCK_CONFIG): $(TEST_ROOT)/JCK-$(JCK_BUNDLE_NAME)-$(JCK_RELEASE)-base.jti + $(RM) $@ + $(MKDIR) -p $(@D) + $(CP) $< $@ + +$(JCK_PROPERTIES): $(PRODUCT_HOME) $(JCK_JAVA_EXE) + $(RM) $@ + $(MKDIR) -p $(@D) + $(ECHO) "jck.env.compiler.compRefExecute.cmdAsFile=$(JCK_JAVA_EXE)" >> $@ + $(ECHO) "jck.env.compiler.compRefExecute.systemRoot=$(SYSTEMROOT)" >> $@ + $(ECHO) "jck.env.compiler.testCompile.testCompileAPImultiJVM.cmdAsFile=$(JCK_JAVA_EXE)" >> $@ + $(ECHO) "jck.tests.tests=$(JCK_BUNDLE_TESTDIRS)" >> $@ + +jck_tests: prep $(JCK_HOME) $(JCK_PROPERTIES) $(JCK_CONFIG) $(JCK_JAVATEST_JAR) + $(MKDIR) -p $(JCK_WORK_DIR) + ( $(JCK_JAVATEST) \ + -verbose:commands,non-pass \ + -testSuite $(JCK_HOME) \ + -workDir $(JCK_WORK_DIR) \ + -config $(JCK_CONFIG) \ + -set -file $(JCK_PROPERTIES) \ + -runtests \ + -writeReport $(JCK_REPORT_DIR) \ + ) ; $(BUNDLE_UP_AND_EXIT) + +PHONY_LIST += jck_tests + +################################################################ + +# jck6 tests + +JCK6_RELEASE = 6b +JCK6_DEFAULT_HOME = $(SLASH_JAVA)/re/jck/$(JCK6_RELEASE)/archive/fcs/binaries + +# Expect JPRT to set JPRT_JCK6COMPILER_HOME. +JCK6COMPILER_HOME = $(JCK6_DEFAULT_HOME)/JCK-compiler-$(JCK6_RELEASE) +ifdef JPRT_JCK6COMPILER_HOME + JCK6COMPILER_HOME = $(JPRT_JCK6COMPILER_HOME) +endif + +# Expect JPRT to set JPRT_JCK6RUNTIME_HOME. +JCK6RUNTIME_HOME = $(JCK6_DEFAULT_HOME)/JCK-runtime-$(JCK6_RELEASE) +ifdef JPRT_JCK6RUNTIME_HOME + JCK6RUNTIME_HOME = $(JPRT_JCK6RUNTIME_HOME) +endif + +# Expect JPRT to set JPRT_JCK6DEVTOOLS_HOME. +JCK6DEVTOOLS_HOME = $(JCK6_DEFAULT_HOME)/JCK-devtools-$(JCK6_RELEASE) +ifdef JPRT_JCK6DEVTOOLS_HOME + JCK6DEVTOOLS_HOME = $(JPRT_JCK6DEVTOOLS_HOME) +endif + +jck6_tests: JCK_HOME=$(JCK6_HOME) +jck6_tests: JCK_RELEASE=$(JCK6_RELEASE) +jck6_tests: jck_tests + +jck6compiler: JCK6_HOME=$(JCK6COMPILER_HOME) +jck6compiler: JCK_BUNDLE_NAME=compiler +jck6compiler: jck6_tests + +jck6compiler_lang: JCK_BUNDLE_TESTDIRS=lang +jck6compiler_lang: jck6compiler + +jck6runtime: JCK6_HOME=$(JCK6RUNTIME_HOME) +jck6runtime: JCK_BUNDLE_NAME=runtime +jck6runtime: jck6_tests + +jck6runtime_lang: JCK_BUNDLE_TESTDIRS=lang +jck6runtime_lang: jck6runtime + +jck6devtools: JCK6_HOME=$(JCK6DEVTOOLS_HOME) +jck6devtools: JCK_BUNDLE_NAME=devtools +jck6devtools: jck6_tests + +jck6devtools_lang: JCK_BUNDLE_TESTDIRS=lang +jck6devtools_lang: jck6devtools + +PHONY_LIST += jck6compiler jck6runtime jck6devtools jck6_tests \ + jck6compiler_lang jck6runtime_lang jck6devtools_lang + +################################################################ + +# jck7 tests + +JCK7_RELEASE = 7 +JCK7_DEFAULT_HOME = $(SLASH_JAVA)/re/jck/$(JCK7_RELEASE)/archive/fcs/binaries + +# Expect JPRT to set JPRT_JCK7COMPILER_HOME. +JCK7COMPILER_HOME = $(JCK7_DEFAULT_HOME)/JCK-compiler-$(JCK7_RELEASE) +ifdef JPRT_JCK7COMPILER_HOME + JCK7COMPILER_HOME = $(JPRT_JCK7COMPILER_HOME) +endif + +# Expect JPRT to set JPRT_JCK7RUNTIME_HOME. +JCK7RUNTIME_HOME = $(JCK7_DEFAULT_HOME)/JCK-runtime-$(JCK7_RELEASE) +ifdef JPRT_JCK7RUNTIME_HOME + JCK7RUNTIME_HOME = $(JPRT_JCK7RUNTIME_HOME) +endif + +# Expect JPRT to set JPRT_JCK7DEVTOOLS_HOME. +JCK7DEVTOOLS_HOME = $(JCK7_DEFAULT_HOME)/JCK-devtools-$(JCK7_RELEASE) +ifdef JPRT_JCK7DEVTOOLS_HOME + JCK7DEVTOOLS_HOME = $(JPRT_JCK7DEVTOOLS_HOME) +endif + +jck7_tests: JCK_HOME=$(JCK7_HOME) +jck7_tests: JCK_RELEASE=$(JCK7_RELEASE) +jck7_tests: jck_tests + +jck7compiler: JCK7_HOME=$(JCK7COMPILER_HOME) +jck7compiler: JCK_BUNDLE_NAME=compiler +jck7compiler: jck7_tests + +jck7compiler_lang: JCK_BUNDLE_TESTDIRS=lang +jck7compiler_lang: jck7compiler + +jck7runtime: JCK7_HOME=$(JCK7RUNTIME_HOME) +jck7runtime: JCK_BUNDLE_NAME=runtime +jck7runtime: jck7_tests + +jck7runtime_lang: JCK_BUNDLE_TESTDIRS=lang +jck7runtime_lang: jck7runtime + +jck7devtools: JCK7_HOME=$(JCK7DEVTOOLS_HOME) +jck7devtools: JCK_BUNDLE_NAME=devtools +jck7devtools: jck7_tests + +jck7devtools_lang: JCK_BUNDLE_TESTDIRS=lang +jck7devtools_lang: jck7devtools + +PHONY_LIST += jck7compiler jck7runtime jck7devtools jck7_tests \ + jck7compiler_lang jck7runtime_lang jck7devtools_lang + +################################################################ # Phony targets (e.g. these are not filenames) -.PHONY: all tests clean check +.PHONY: all clean prep $(PHONY_LIST) + +################################################################ From c9ce349372fe80f7b0e4cf2da2fd18156a417452 Mon Sep 17 00:00:00 2001 From: Kelly O'Hair Date: Tue, 31 Mar 2009 16:14:14 -0700 Subject: [PATCH 60/75] 6824012: Add jdk regression tests to default jprt jobs A work in progress on adding to the jprt testing. Reviewed-by: tbell --- jdk/make/jprt.properties | 13 +++++++++++++ jdk/test/java/io/File/GetXSpace.java | 1 + jdk/test/java/lang/Thread/StartOOMTest.java | 1 + jdk/test/java/util/logging/LoggingDeadlock2.java | 2 +- 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/jdk/make/jprt.properties b/jdk/make/jprt.properties index c909f36aa3c..a1e7e5100ba 100644 --- a/jdk/make/jprt.properties +++ b/jdk/make/jprt.properties @@ -53,6 +53,19 @@ jprt.solaris_x64.build.platform.match32=solaris_i586_5.10 # Standard list of jprt test targets for this workspace jprt.test.targets=*-*-*-jvm98 +jprt.regression.test.targets= \ + *-*-*-java/lang, \ + *-*-*-java/security, \ + *-*-*-java/text, \ + *-*-*-java/util + +#jprt.regression.test.targets= \ +# *-*-*-java/awt, \ +# *-*-*-java/beans, \ +# *-*-*-java/io, \ +# *-*-*-java/net, \ +# *-*-*-java/nio, \ +# *-*-*-java/rmi, \ # Directories needed to build jprt.bundle.exclude.src.dirs=build diff --git a/jdk/test/java/io/File/GetXSpace.java b/jdk/test/java/io/File/GetXSpace.java index a2855e7b372..345c3384668 100644 --- a/jdk/test/java/io/File/GetXSpace.java +++ b/jdk/test/java/io/File/GetXSpace.java @@ -24,6 +24,7 @@ /** * @test * @bug 4057701 6286712 6364377 + * @ignore until 6492634 and 6501010 is fixed * @run build GetXSpace * @run shell GetXSpace.sh * @summary Basic functionality of File.get-X-Space methods. diff --git a/jdk/test/java/lang/Thread/StartOOMTest.java b/jdk/test/java/lang/Thread/StartOOMTest.java index dd8b519453e..260d0929703 100644 --- a/jdk/test/java/lang/Thread/StartOOMTest.java +++ b/jdk/test/java/lang/Thread/StartOOMTest.java @@ -24,6 +24,7 @@ /* * @test * @bug 6379235 + * @ignore until 6721694 is fixed * @run main/othervm -server -Xmx32m -Xms32m -Xss256m StartOOMTest * @summary ThreadGroup accounting mistake possible with failure of Thread.start() */ diff --git a/jdk/test/java/util/logging/LoggingDeadlock2.java b/jdk/test/java/util/logging/LoggingDeadlock2.java index 47831935226..50de62abfcc 100644 --- a/jdk/test/java/util/logging/LoggingDeadlock2.java +++ b/jdk/test/java/util/logging/LoggingDeadlock2.java @@ -24,7 +24,7 @@ /* * @test * @bug 6467152 - * + * @ignore until 6716076 is fixed * @summary deadlock occurs in LogManager initialization and JVM termination * @author Serguei Spitsyn / Hittachi * From c81e6c29c17c27ad6c0a4e857582ba2f937a7aba Mon Sep 17 00:00:00 2001 From: Tim Bell Date: Wed, 1 Apr 2009 04:44:30 -0700 Subject: [PATCH 61/75] 6824595: OpenJDK fix breaks product build for jdk7 Reviewed-by: xdono, ohair --- jdk/make/Makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/jdk/make/Makefile b/jdk/make/Makefile index 27781781f62..c78e4c27e01 100644 --- a/jdk/make/Makefile +++ b/jdk/make/Makefile @@ -328,6 +328,11 @@ else $(ECHO) "Rule $@ does not apply on $(PLATFORM)-$(ARCH)" endif +# +# Binary Plug rules and macros +# +include $(BUILDDIR)/common/internal/BinaryPlugs.gmk + # # Get top level sccs_get rule # From 1e18bf2d6e535a8c774f91d33809ea3fa638ee18 Mon Sep 17 00:00:00 2001 From: Kelly O'Hair Date: Wed, 1 Apr 2009 09:08:54 -0700 Subject: [PATCH 62/75] 6824583: regtest TimeUnit/Basic.java fails intermittently on Windows - again Reviewed-by: dholmes --- jdk/test/java/util/concurrent/TimeUnit/Basic.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/jdk/test/java/util/concurrent/TimeUnit/Basic.java b/jdk/test/java/util/concurrent/TimeUnit/Basic.java index 7a956410231..bae284d6c88 100644 --- a/jdk/test/java/util/concurrent/TimeUnit/Basic.java +++ b/jdk/test/java/util/concurrent/TimeUnit/Basic.java @@ -60,10 +60,11 @@ public class Basic { equal(1000L, MICROSECONDS.toNanos(1)); long t0 = System.nanoTime(); - MILLISECONDS.sleep(3); + MILLISECONDS.sleep(3); /* See windows bug 6313903, might not sleep */ long elapsedMillis = (System.nanoTime() - t0)/(1000L * 1000L); System.out.printf("elapsed=%d%n", elapsedMillis); - check(elapsedMillis >= 3); + check(elapsedMillis >= 0); + /* Might not sleep on windows: check(elapsedMillis >= 3); */ check(elapsedMillis < 1000); //---------------------------------------------------------------- From 8ed0a99cb648cf35658e32449104ae86cdcb8c7b Mon Sep 17 00:00:00 2001 From: Kelly O'Hair Date: Wed, 1 Apr 2009 16:49:43 -0700 Subject: [PATCH 63/75] 6825175: Remove or disable sanity check on binary plugs Reviewed-by: xdono --- jdk/make/common/shared/Sanity.gmk | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/jdk/make/common/shared/Sanity.gmk b/jdk/make/common/shared/Sanity.gmk index 23e3818353b..180e52196a9 100644 --- a/jdk/make/common/shared/Sanity.gmk +++ b/jdk/make/common/shared/Sanity.gmk @@ -502,13 +502,15 @@ endif ###################################################### ifdef OPENJDK sane-binary-plugs: + ifeq ($(IMPORT_BINARY_PLUGS),true) @if [ ! -d "$(BINARY_PLUGS_PATH)" ]; then \ - $(ECHO) "ERROR: Can't locate pre-built libraries. \n" \ + $(ECHO) "WARNING: Can't locate pre-built libraries. \n" \ " Please check your access to \n" \ " $(BINARY_PLUGS_PATH) \n" \ " and/or check your value of ALT_BINARY_PLUGS_PATH. \n" \ - "" >> $(ERROR_FILE); \ + "" >> $(WARNING_FILE); \ fi + endif endif ###################################################### From 208dfa22cd051963f5b9feda33d74da3eeed189d Mon Sep 17 00:00:00 2001 From: Kelly O'Hair Date: Thu, 2 Apr 2009 15:04:33 -0700 Subject: [PATCH 64/75] 6825765: Further adjustments to regression tests run by jprt Reviewed-by: tbell --- jdk/test/java/lang/reflect/Method/InheritedMethods.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/test/java/lang/reflect/Method/InheritedMethods.java b/jdk/test/java/lang/reflect/Method/InheritedMethods.java index 943767fb85f..7b54f7b1edc 100644 --- a/jdk/test/java/lang/reflect/Method/InheritedMethods.java +++ b/jdk/test/java/lang/reflect/Method/InheritedMethods.java @@ -23,6 +23,7 @@ /* @test @bug 4471738 + @ignore until 6825739 fixed @summary Failure to properly traverse class hierarchy in Class.getMethod() */ From 21e44848b0b8c95e44be126e96e69d1a29ffc6e1 Mon Sep 17 00:00:00 2001 From: Xiomara Jayasena Date: Thu, 2 Apr 2009 16:51:36 -0700 Subject: [PATCH 65/75] Added tag jdk7-b53 for changeset 149237542285 --- .hgtags-top-repo | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags-top-repo b/.hgtags-top-repo index 5ac8ad95712..a3bb161285f 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -27,3 +27,4 @@ aee93a8992d2389121eb610c00a86196f3e2b9b0 jdk7-b49 5111e13e44e542fe945b47ab154546daec36737d jdk7-b50 0f0189d55ce4a1f7840da7582ac7d970b3b7ab15 jdk7-b51 4264c2fe66493e57c411045a1b61377796641e45 jdk7-b52 +c235f4a8559d196879c56af80159f67ee5d0e720 jdk7-b53 From a91d2cfe7afc0145ec28c7b2069109962d76a81e Mon Sep 17 00:00:00 2001 From: Xiomara Jayasena Date: Thu, 2 Apr 2009 16:51:38 -0700 Subject: [PATCH 66/75] Added tag jdk7-b53 for changeset 66f056cc8fd4 --- corba/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/corba/.hgtags b/corba/.hgtags index 91ac5a1ccae..8ad020f432f 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -27,3 +27,4 @@ d70978bc64bc7a04be7797ab0dcd9b7b1b3a6bff jdk7-b49 0edbd0074b02b42b2b83cc47cb391d4869b7a8ec jdk7-b50 3eb8f1047a7402a9a79937d1c39560e931e91da2 jdk7-b51 bec82237d694f9802b820fa11bbb4f7fa9bf8e77 jdk7-b52 +3c4d73194f6f89f040ae3b2d257335dfa8a1b2b5 jdk7-b53 From f907f0a9d24e050a6678ea0d347c5220349d9a70 Mon Sep 17 00:00:00 2001 From: Xiomara Jayasena Date: Thu, 2 Apr 2009 16:51:41 -0700 Subject: [PATCH 67/75] Added tag jdk7-b53 for changeset 94c3ff1a20d0 --- hotspot/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 475bfa37988..30fc9e5e179 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -27,3 +27,4 @@ bcb33806d186561c781992e5f4d8a90bb033f9f0 jdk7-b48 dae503d9f04c1a11e182dbf7f770509c28dc0609 jdk7-b50 2581d90c6c9b2012da930eb4742add94a03069a0 jdk7-b51 1b1e8f1a4fe8cebc01c022484f78148e17b62a0d jdk7-b52 +032c6af894dae8d939b3dd31d82042549e7793e0 jdk7-b53 From b1371af3b757bb37b54a90b854a18a8907b96b5c Mon Sep 17 00:00:00 2001 From: Xiomara Jayasena Date: Thu, 2 Apr 2009 16:51:46 -0700 Subject: [PATCH 68/75] Added tag jdk7-b53 for changeset d14d2d3caaf1 --- jaxp/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxp/.hgtags b/jaxp/.hgtags index 8951b3d1ac5..d1208e38760 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -27,3 +27,4 @@ d711ad1954b294957737ea386cfd4d3c05028a36 jdk7-b47 e8514e2be76d90889ebdb90d627aca2db5c150c6 jdk7-b50 ae890d80d5dffcd4dc77a1f17d768e192d1852c7 jdk7-b51 69ad87dc25cbcaaaded4727199395ad0c78bc427 jdk7-b52 +e8837366d3fd72f7c7a47ebfdbd5106c16156f12 jdk7-b53 From 223f8354addce077625f9c3374ea5d54a58a119a Mon Sep 17 00:00:00 2001 From: Xiomara Jayasena Date: Thu, 2 Apr 2009 16:51:48 -0700 Subject: [PATCH 69/75] Added tag jdk7-b53 for changeset b52ef22dd797 --- jaxws/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxws/.hgtags b/jaxws/.hgtags index 62bf7fdbd4d..0aca2ee92b5 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -27,3 +27,4 @@ af4a3eeb7812a5d09a241c50b51b3c648a9d45c1 jdk7-b46 5be52db581f1ea91ab6e0eb34ba7f439125bfb16 jdk7-b50 41a66a42791ba90bff489af72cbfea71be9b40a5 jdk7-b51 e646890d18b770f625f14ed4ad5c50554d8d3d8b jdk7-b52 +b250218eb2e534384667ec73e3713e684667fd4c jdk7-b53 From 9d4aff2eaf2760e6c1b328e8a3552552b3e8ed2d Mon Sep 17 00:00:00 2001 From: Xiomara Jayasena Date: Thu, 2 Apr 2009 16:51:55 -0700 Subject: [PATCH 70/75] Added tag jdk7-b53 for changeset 05e04a29c589 --- jdk/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/.hgtags b/jdk/.hgtags index 39ec72bb7a9..a611fd31d77 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -27,3 +27,4 @@ b4ac413b1f129eeef0acab3f31081c1b7dfe3b27 jdk7-b47 58ba2cd5a25053684ec53205d95edeeaa0006f13 jdk7-b50 fea0898259ae41c73620b1815aa48f036216155c jdk7-b51 bcbeadb4a5d759b29e876ee2c83401e91ff22f60 jdk7-b52 +a2033addca678f9e4c0d92ffa1e389171cc9321d jdk7-b53 From 6103649b6b24549638bf78d99b9dff0989da668e Mon Sep 17 00:00:00 2001 From: Xiomara Jayasena Date: Thu, 2 Apr 2009 16:52:05 -0700 Subject: [PATCH 71/75] Added tag jdk7-b53 for changeset e053a98a8120 --- langtools/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/langtools/.hgtags b/langtools/.hgtags index 0ea2c411d86..20846492199 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -27,3 +27,4 @@ d17d927ad9bdfafae32451645d182acb7bed7be6 jdk7-b49 46f2f6ed96f13fc49fec3d1b6aa616686128cb57 jdk7-b50 8c55d5b0ed71ed3a749eb97e4eab79b4831649b8 jdk7-b51 29329051d483d39f66073752ba4afbf29d893cfe jdk7-b52 +dbdeb4a7581b2a8699644b91cae6793cb01953f7 jdk7-b53 From 067a3d9ad63aae04be1c0b52ca10026b11a4f68e Mon Sep 17 00:00:00 2001 From: Erik Trimble Date: Thu, 2 Apr 2009 17:37:07 -0700 Subject: [PATCH 72/75] 6825815: Bump HS15 build number to 05 and update copyright date of HOTSPOT_VM_COPYRIGHT Update the HS15 Build number to 05 and fix copyright date of HOTSPOT_VM_COPYRIGHT Reviewed-by: jcoomes --- hotspot/make/hotspot_version | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hotspot/make/hotspot_version b/hotspot/make/hotspot_version index f3f6bc5d15b..64a2efe6dd1 100644 --- a/hotspot/make/hotspot_version +++ b/hotspot/make/hotspot_version @@ -31,11 +31,11 @@ # # Don't put quotes (fail windows build). -HOTSPOT_VM_COPYRIGHT=Copyright 2008 +HOTSPOT_VM_COPYRIGHT=Copyright 2009 HS_MAJOR_VER=15 HS_MINOR_VER=0 -HS_BUILD_NUMBER=04 +HS_BUILD_NUMBER=05 JDK_MAJOR_VER=1 JDK_MINOR_VER=7 From fd20a6a950c588757419824103aff4d0f2b636a4 Mon Sep 17 00:00:00 2001 From: "J. Duke" Date: Wed, 5 Jul 2017 16:49:29 +0200 Subject: [PATCH 73/75] Added tag jdk7-b52 for changeset 7a90e89e36d1 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 89f5f016035..6d54fecdbfa 100644 --- a/.hgtags +++ b/.hgtags @@ -26,3 +26,4 @@ caf58ffa084568990cbb3441f9ae188e36b31770 jdk7-b42 6b84b04a80afe23262377c60913eebfc898f14c4 jdk7-b49 5da0e6b9f4f18ef483c977337214b12ee0e1fc8f jdk7-b50 a25c5ec5e40e07733d1ff9898a0abe36159288ff jdk7-b51 +7a90e89e36d103038f8667f6a7daae34ecfa1ad8 jdk7-b52 From 1fcb5893bd7f30a067db966cffc735bec114715a Mon Sep 17 00:00:00 2001 From: "J. Duke" Date: Wed, 5 Jul 2017 16:50:04 +0200 Subject: [PATCH 74/75] Added tag jdk7-b53 for changeset d52186ee770d --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 6d54fecdbfa..d0000317c40 100644 --- a/.hgtags +++ b/.hgtags @@ -27,3 +27,4 @@ caf58ffa084568990cbb3441f9ae188e36b31770 jdk7-b42 5da0e6b9f4f18ef483c977337214b12ee0e1fc8f jdk7-b50 a25c5ec5e40e07733d1ff9898a0abe36159288ff jdk7-b51 7a90e89e36d103038f8667f6a7daae34ecfa1ad8 jdk7-b52 +d52186ee770dac57950536cd00ccbfdef360b04c jdk7-b53 From 1f75d1c6dd8d2c835b8bf0507ce3d3b94b496ea4 Mon Sep 17 00:00:00 2001 From: Erik Trimble Date: Wed, 8 Apr 2009 14:55:38 -0700 Subject: [PATCH 75/75] 6828076: Fork HS15 to HS16 - renumber Major and build numbers of JVM Update the Hotspot version number to HS16 B01 for HS16 fork Reviewed-by: jcoomes --- hotspot/make/hotspot_version | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hotspot/make/hotspot_version b/hotspot/make/hotspot_version index 64a2efe6dd1..a99670bda35 100644 --- a/hotspot/make/hotspot_version +++ b/hotspot/make/hotspot_version @@ -33,9 +33,9 @@ # Don't put quotes (fail windows build). HOTSPOT_VM_COPYRIGHT=Copyright 2009 -HS_MAJOR_VER=15 +HS_MAJOR_VER=16 HS_MINOR_VER=0 -HS_BUILD_NUMBER=05 +HS_BUILD_NUMBER=01 JDK_MAJOR_VER=1 JDK_MINOR_VER=7

" + NL + + "Class Summary" + NL + + "Interface Summary" + NL + + "Enum Summary" + NL + + "Annotation Types Summary" + NL + + "Field Summary" + NL + + "Method Summary" + NL + + "Nested Class Summary" + NL + + "Constructor Summary" + NL + + "Enum Constant Summary" + NL + + "Required Element Summary" + NL + + "Optional Element Summary" + NL + + "Packages that use I1" + NL + + "Fields in pkg2 " + + "declared as " + + "C1" + NL + + "Methods in pkg2 " + + "with parameters of type C1" + NL + + "Fields in pkg1 " + + "declared as " + + "C2" + NL + + "Methods in pkg1 " + + "with parameters of type C2" + NL + + "Methods in pkg2 " + + "that return C2.ModalExclusionType" + NL + + "Packages that use " + + "pkg1" + NL + + "Classes in pkg1 " + + "used by pkg1" + NL + + "Packages that use " + + "pkg2" + NL + + "Classes in pkg2 " + + "used by pkg1" + NL + + "Deprecated Fields" + NL + + "Deprecated Methods" + NL + + "pkg1.C1" + NL + + "Packages
" + + "ClassDescription" + + "InterfaceDescription" + + "EnumDescription" + + "Annotation TypeDescription" + + "Modifier and TypeField and Description" + + "Modifier and TypeMethod and Description" + + "Modifier and TypeClass and Description" + + "Constructor and Description" + + "Enum Constant and Description" + + "Modifier and TypeRequired Element and Description" + + "Modifier and TypeOptional Element and Description" + + "PackageDescription" + + "Modifier and TypeField and Description" + + "Modifier and TypeMethod and Description" + + "Modifier and TypeField and Description" + + "Modifier and TypeMethod and Description" + + "PackageDescription" + + "Modifier and TypeMethod and Description" + + "PackageDescription" + + "Class and Description" + + "PackageDescription" + + "Class and Description" + + "Field and Description" + + "Method and Description" + + "Modifier and TypeConstant FieldValue" + + "PackageDescription
" + NL + + "Enum Constant Summary" + NL + + "Required Element Summary" + NL + + "Optional Element Summary
Classes in pkg2 with type parameters of type Foo
" + NL + + "Classes in pkg2" + + " with type parameters of type Foo
ClassUseTest1<T extends Foo & Foo2>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo.html", - "Methods in pkg2 with type parameters of type Foo
" + NL + + "Methods in pkg2" + + " with type parameters of type Foo
ClassUseTest1.method(T t)" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo.html", - "Fields in pkg2 with type parameters of type Foo
" + NL + + "Fields in pkg2" + + " with type parameters of type Foo
Fields in pkg2 declared as ParamTest
" + NL + + "Fields in pkg2" + + " declared as ParamTest
Classes in pkg2 with type parameters of type Foo2
" + NL + + "Classes in pkg2" + + " with type parameters of type Foo2
ClassUseTest1<T extends Foo & Foo2>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo2.html", - "Methods in pkg2 with type parameters of type Foo2
" + NL + + "Methods in pkg2" + + " with type parameters of type Foo2
ClassUseTest1.method(T t)" @@ -326,44 +347,66 @@ public class TestNewLanguageFeatures extends JavadocTester { //ClassUseTest2: > {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", - "Classes in pkg2 with type parameters of type ParamTest
" + NL + + "Classes in pkg2" + + " with type parameters of type ParamTest
ClassUseTest2<T extends ParamTest<Foo3>>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", - "Methods in pkg2 with type parameters of type ParamTest
" + NL + + "Methods in pkg2" + + " with type parameters of type ParamTest
ClassUseTest2.method(T t)" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", - "Fields in pkg2 declared as ParamTest
" + NL + + "Fields in pkg2" + + " declared as ParamTest
Methods in pkg2 with type parameters of type ParamTest
" + NL + + "Methods in pkg2" + + " with type parameters of type ParamTest
Classes in pkg2 with type parameters of type Foo3
" + NL + + "Classes in pkg2" + + " with type parameters of type Foo3
ClassUseTest2<T extends ParamTest<Foo3>>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo3.html", - "Methods in pkg2 with type parameters of type Foo3
" + NL + + "Methods in pkg2" + + " with type parameters of type Foo3
ClassUseTest2.method(T t)" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo3.html", - "Methods in pkg2 that return types with arguments of type Foo3
" + NL + + "Methods in pkg2" + + " that return types with arguments of type " + + "" + + "Foo3
Classes in pkg2 with type parameters of type ParamTest2
" + NL + + "Classes in pkg2" + + " with type parameters of type " + + "" + + "ParamTest2
ClassUseTest3<T extends ParamTest2<java.util.List<? extends Foo4>>>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest2.html", - "Methods in pkg2 with type parameters of type ParamTest2
" + NL + + "Methods in pkg2" + + " with type parameters of type " + + "" + + "ParamTest2
ClassUseTest3.method(T t)" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest2.html", - "Methods in pkg2 with type parameters of type ParamTest2
" + NL + + "Methods in pkg2" + + " with type parameters of type " + + "" + + "ParamTest2
Classes in pkg2 with type parameters of type Foo4
" + NL + + "Classes in pkg2" + + " with type parameters of type " + + "" + + "Foo4
ClassUseTest3<T extends ParamTest2<java.util.List<? extends Foo4>>>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo4.html", - "Methods in pkg2 with type parameters of type Foo4
" + NL + + "Methods in pkg2" + + " with type parameters of type Foo4
ClassUseTest3.method(T t)" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo4.html", - "Methods in pkg2 that return types with arguments of type Foo4
" + NL + + "Methods in pkg2" + + " that return types with arguments of type " + + "" + + "Foo4
Method parameters in pkg2 with type arguments of type Foo4
" + NL + - " voidClassUseTest3.method(java.util.Set<Foo4> p)" + "
" + NL + + "Method parameters in pkg2" + + " with type arguments of type Foo4
Modifier and Type" + + "Method and Description
" + NL + + " voidClassUseTest3." + + "" + + "method(java.util.Set<Foo4> p)" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo4.html", - "Constructor parameters in pkg2 with type arguments of type Foo4
ClassUseTest3(java.util.Set<Foo4> p)" + "
" + NL + + "Constructor parameters in " + + "pkg2 with type arguments of type Foo4
Constructor and Description" + + "
ClassUseTest3(java.util.Set<" + + "" + + "Foo4> p)" }, //================================= // Annotatation Type Usage //================================= {BUG_ID + FS + "pkg" + FS + "class-use" + FS + "AnnotationType.html", - "" + NL + - "Packages with annotations of type AnnotationType" + NL + - "
pkg
Package" + + "Description
pkg" + + "
" + NL + - " classAnnotationTypeUsage" + "Classes in pkg" + + " with annotations of type AnnotationType" + NL + + "
Modifier and Type" + + "Class and Description
" + NL + + " classAnnotationTypeUsage" }, {BUG_ID + FS + "pkg" + FS + "class-use" + FS + "AnnotationType.html", - "Fields in pkg with annotations of type AnnotationType" + NL + - "
" + NL + - " intAnnotationTypeUsage.field" + "Fields in pkg" + + " with annotations of type AnnotationType" + NL + + "
Modifier and Type" + + "Field and Description
" + NL + + " intAnnotationTypeUsage." + + "field" + + "" }, {BUG_ID + FS + "pkg" + FS + "class-use" + FS + "AnnotationType.html", - "Methods in pkg with annotations of type AnnotationType" + NL + - "
" + NL + - " voidAnnotationTypeUsage.method()" + "Methods in pkg" + + " with annotations of type AnnotationType" + NL + + "
Modifier and Type" + + "Method and Description
" + NL + + " voidAnnotationTypeUsage." + + "" + + "method()" }, {BUG_ID + FS + "pkg" + FS + "class-use" + FS + "AnnotationType.html", - "Method parameters in pkg with annotations of type AnnotationType" + NL + - "
" + NL + - " voidAnnotationTypeUsage.methodWithParams(int documented," + NL + - " int undocmented)" + "Method parameters in pkg" + + " with annotations of type AnnotationType" + NL + + "
Modifier and Type" + + "Method and Description
" + NL + + " voidAnnotationTypeUsage." + + "methodWithParams(int documented," + NL + + " int undocmented)" }, {BUG_ID + FS + "pkg" + FS + "class-use" + FS + "AnnotationType.html", - "Constructors in pkg with annotations of type AnnotationType" + NL + - "
AnnotationTypeUsage()" + "Constructors in pkg" + + " with annotations of type AnnotationType" + NL + + "
Constructor and Description" + + "
" + + "AnnotationTypeUsage()" }, {BUG_ID + FS + "pkg" + FS + "class-use" + FS + "AnnotationType.html", - "Constructor parameters in pkg with annotations of type AnnotationType" + NL + - "
AnnotationTypeUsage(int documented," + NL + - " int undocmented)" + "Constructor parameters in pkg" + + " with annotations of type AnnotationType" + NL + + "
Constructor and Description" + + "
" + + "AnnotationTypeUsage(int documented," + NL + + " int undocmented)" }, //================================= diff --git a/langtools/test/com/sun/javadoc/testSummaryHeading/TestSummaryHeading.java b/langtools/test/com/sun/javadoc/testSummaryHeading/TestSummaryHeading.java index 36cd089c32f..49aafe21ffc 100644 --- a/langtools/test/com/sun/javadoc/testSummaryHeading/TestSummaryHeading.java +++ b/langtools/test/com/sun/javadoc/testSummaryHeading/TestSummaryHeading.java @@ -46,7 +46,8 @@ public class TestSummaryHeading extends JavadocTester { //Input for string search tests. private static final String[][] TEST = { - {BUG_ID + FS + "C.html", "Method Summary"} + {BUG_ID + FS + "C.html", "
" + NL + + "Method Summary