--- /dev/null Wed May 20 18:55:38 2009 +++ new/make/tools/src/build/tools/charsetmapping/GenerateDBCS.java Wed May 20 18:55:36 2009 @@ -0,0 +1,285 @@ +/* + * 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 build.tools.charsetmapping; +import java.io.*; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Scanner; +import java.util.Formatter; +import java.util.regex.*; +import java.nio.charset.*; +import static build.tools.charsetmapping.CharsetMapping.*; + +public class GenerateDBCS { + // pattern used by this class to read in mapping table + static Pattern mPattern = Pattern.compile("(\\p{XDigit}++)\\s++(\\p{XDigit}++)(\\s++#.*)?"); + public static void genDBCS(String args[]) throws Exception { + + Scanner s = new Scanner(new File(args[0], args[2])); + while (s.hasNextLine()) { + String line = s.nextLine(); + if (line.startsWith("#") || line.length() == 0) + continue; + String[] fields = line.split("\\s+"); + if (fields.length < 10) { + System.err.println("Misconfiged sbcs line <" + line + ">?"); + continue; + } + String clzName = fields[0]; + String csName = fields[1]; + String hisName = ("null".equals(fields[2]))?null:fields[2]; + String type = fields[3].toUpperCase(); + if ("BASIC".equals(type)) + type = ""; + else + type = "_" + type; + String pkgName = fields[4]; + boolean isASCII = Boolean.valueOf(fields[5]); + int b1Min = toInteger(fields[6]); + int b1Max = toInteger(fields[7]); + int b2Min = toInteger(fields[8]); + int b2Max = toInteger(fields[9]); + System.out.printf("%s,%s,%s,%b,%s%n", clzName, csName, hisName, isASCII, pkgName); + genClass(args[0], args[1], "DoubleByte-X.java", + clzName, csName, hisName, pkgName, + isASCII, type, + b1Min, b1Max, b2Min, b2Max); + } + } + + private static int toInteger(String s) { + if (s.startsWith("0x") || s.startsWith("0X")) + return Integer.valueOf(s.substring(2), 16); + else + return Integer.valueOf(s); + } + + private static void outString(Formatter out, + char[] cc, int off, int end, + String closure) + { + while (off < end) { + out.format(" \""); + for (int j = 0; j < 8; j++) { + if (off == end) + break; + char c = cc[off++]; + switch (c) { + case '\b': + out.format("\\b"); break; + case '\t': + out.format("\\t"); break; + case '\n': + out.format("\\n"); break; + case '\f': + out.format("\\f"); break; + case '\r': + out.format("\\r"); break; + case '\"': + out.format("\\\""); break; + case '\'': + out.format("\\'"); break; + case '\\': + out.format("\\\\"); break; + default: + out.format("\\u%04X", c & 0xffff); + } + } + if (off == end) + out.format("\" %s%n", closure); + else + out.format("\" + %n"); + } + } + + private static void outString(Formatter out, + char[] db, + int b1, + int b2Min, int b2Max, + String closure) + { + char[] cc = new char[b2Max - b2Min + 1]; + int off = 0; + for (int b2 = b2Min; b2 <= b2Max; b2++) { + cc[off++] = db[(b1 << 8) | b2]; + } + outString(out, cc, 0, cc.length, closure); + } + + private static void genClass(String srcDir, String dstDir, String template, + String clzName, + String csName, + String hisName, + String pkgName, + boolean isASCII, + String type, + int b1Min, int b1Max, + int b2Min, int b2Max) + throws Exception + { + + StringBuilder b2cSB = new StringBuilder(); + StringBuilder b2cNRSB = new StringBuilder(); + StringBuilder c2bNRSB = new StringBuilder(); + + char[] db = new char[0x10000]; + char[] c2bIndex = new char[0x100]; + int c2bOff = 0x100; // first 0x100 for unmappable segs + + Arrays.fill(db, UNMAPPABLE_DECODING); + Arrays.fill(c2bIndex, UNMAPPABLE_DECODING); + + char[] b2cIndex = new char[0x100]; + Arrays.fill(b2cIndex, UNMAPPABLE_DECODING); + + // (1)read in .map to parse all b->c entries + FileInputStream in = new FileInputStream(new File(srcDir, clzName + ".map")); + Parser p = new Parser(in, mPattern); + Entry e = null; + while ((e = p.next()) != null) { + db[e.bs] = (char)e.cp; + + if (e.bs > 0x100 && // db + b2cIndex[e.bs>>8] == UNMAPPABLE_DECODING) { + b2cIndex[e.bs>>8] = 1; + } + + if (c2bIndex[e.cp>>8] == UNMAPPABLE_DECODING) { + c2bOff += 0x100; + c2bIndex[e.cp>>8] = 1; + } + } + Formatter fm = new Formatter(b2cSB); + fm.format("%n static final String b2cSBStr =%n"); + outString(fm, db, 0x00, 0x100, ";"); + + fm.format("%n static final String[] b2cStr = {%n"); + for (int i = 0; i < 0x100; i++) { + if (b2cIndex[i] == UNMAPPABLE_DECODING) { + fm.format(" null,%n"); //unmappable segments + } else { + outString(fm, db, i, b2Min, b2Max, ","); + } + } + + fm.format(" };%n"); + fm.close(); + + // (2)now parse the .nr file which includes "b->c" non-roundtrip entries + File f = new File(srcDir, clzName + ".nr"); + if (f.exists()) { + StringBuilder sb = new StringBuilder(); + in = new FileInputStream(f); + p = new Parser(in, mPattern); + e = null; + while ((e = p.next()) != null) { + // A pair + sb.append((char)e.bs); + sb.append((char)e.cp); + } + char[] nr = sb.toString().toCharArray(); + fm = new Formatter(b2cNRSB); + fm.format("String b2cNR =%n"); + outString(fm, nr, 0, nr.length, ";"); + fm.close(); + } else { + b2cNRSB.append("String b2cNR = null;"); + } + + // (3)finally the .c2b file which includes c->b non-roundtrip entries + f = new File(srcDir, clzName + ".c2b"); + if (f.exists()) { + StringBuilder sb = new StringBuilder(); + in = new FileInputStream(f); + p = new Parser(in, mPattern); + e = null; + while ((e = p.next()) != null) { + // A pair + if (c2bIndex[e.cp>>8] == UNMAPPABLE_DECODING) { + c2bOff += 0x100; + c2bIndex[e.cp>>8] = 1; + } + sb.append((char)e.bs); + sb.append((char)e.cp); + } + char[] nr = sb.toString().toCharArray(); + fm = new Formatter(c2bNRSB); + fm.format("String c2bNR =%n"); + outString(fm, nr, 0, nr.length, ";"); + fm.close(); + } else { + c2bNRSB.append("String c2bNR = null;"); + } + + // (4)it's time to generate the source file + String b2c = b2cSB.toString(); + String b2cNR = b2cNRSB.toString(); + String c2bNR = c2bNRSB.toString(); + + Scanner s = new Scanner(new File(srcDir, template)); + PrintStream out = new PrintStream(new FileOutputStream( + new File(dstDir, clzName + ".java"))); + if (hisName == null) + hisName = ""; + + while (s.hasNextLine()) { + String line = s.nextLine(); + if (line.indexOf("$") == -1) { + out.println(line); + continue; + } + line = line.replace("$PACKAGE$" , pkgName) + .replace("$IMPLEMENTS$", (hisName == null)? + "" : "implements HistoricallyNamedCharset") + .replace("$NAME_CLZ$", clzName) + .replace("$NAME_ALIASES$", + "sun.nio.cs".equals(pkgName) ? + "StandardCharsets.aliases_" + clzName : + "ExtendedCharsets.aliasesFor(\"" + csName + "\")") + .replace("$NAME_CS$" , csName) + .replace("$CONTAINS$", isASCII ? + " return ((cs.name().equals(\"US-ASCII\")) || (cs instanceof " + + clzName + "));": + " return (cs instanceof " + clzName + ");") + .replace("$HISTORICALNAME$", + (hisName == null)? "" : + " public String historicalName() { return \"" + hisName + "\"; }") + .replace("$DECTYPE$", type) + .replace("$ENCTYPE$", type) + .replace("$B1MIN$" , "0x" + Integer.toString(b1Min, 16)) + .replace("$B1MAX$" , "0x" + Integer.toString(b1Max, 16)) + .replace("$B2MIN$" , "0x" + Integer.toString(b2Min, 16)) + .replace("$B2MAX$" , "0x" + Integer.toString(b2Max, 16)) + .replace("$B2C$", b2c) + .replace("$C2BLENGTH$", "0x" + Integer.toString(c2bOff, 16)) + .replace("$NONROUNDTRIP_B2C$", b2cNR) + .replace("$NONROUNDTRIP_C2B$", c2bNR); + + out.println(line); + } + out.close(); + } +}