1 /* 2 * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Sun designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Sun in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 22 * CA 95054 USA or visit www.sun.com if you need additional information or 23 * have any questions. 24 */ 25 26 package build.tools.charsetmapping; 27 28 import java.io.*; 29 import java.util.Arrays; 30 import java.util.ArrayList; 31 import java.util.Scanner; 32 import java.util.Formatter; 33 import java.util.regex.*; 34 import java.nio.charset.*; 35 import static build.tools.charsetmapping.CharsetMapping.*; 36 37 public class GenerateSBCS { 38 39 public static void genSBCS(String args[]) throws Exception { 40 41 Scanner s = new Scanner(new File(args[0], args[2])); 42 while (s.hasNextLine()) { 43 String line = s.nextLine(); 44 if (line.startsWith("#") || line.length() == 0) 45 continue; 46 String[] fields = line.split("\\s+"); 47 if (fields.length < 5) { 48 System.err.println("Misconfiged sbcs line <" + line + ">?"); 49 continue; 50 } 51 String clzName = fields[0]; 52 String csName = fields[1]; 53 String hisName = fields[2]; 54 boolean isASCII = Boolean.valueOf(fields[3]); 55 String pkgName = fields[4]; 56 System.out.printf("%s,%s,%s,%b,%s%n", clzName, csName, hisName, isASCII, pkgName); 57 58 genClass(args[0], args[1], "SingleByte-X.java", 59 clzName, csName, hisName, pkgName, isASCII); 60 } 61 } 62 63 private static void toString(char[] sb, int off, int end, 64 Formatter out, String closure, 65 boolean comment) { 66 while (off < end) { 67 out.format(" \""); 68 for (int j = 0; j < 8; j++) { 69 if (off == end) 70 break; 71 char c = sb[off++]; 72 switch (c) { 73 case '\b': 74 out.format("\\b"); break; 75 case '\t': 76 out.format("\\t"); break; 77 case '\n': 78 out.format("\\n"); break; 79 case '\f': 80 out.format("\\f"); break; 81 case '\r': 82 out.format("\\r"); break; 83 case '\"': 84 out.format("\\\""); break; 85 case '\'': 86 out.format("\\'"); break; 87 case '\\': 88 out.format("\\\\"); break; 89 default: 90 out.format("\\u%04X", c & 0xffff); 91 } 92 } 93 if (comment) { 94 if (off == end) 95 out.format("\" %s // 0x%02x - 0x%02x%n", 96 closure, off-8, off-1); 97 else 98 out.format("\" + // 0x%02x - 0x%02x%n", 99 off-8, off-1); 100 } else { 101 if (off == end) 102 out.format("\"%s%n", closure); 103 else 104 out.format("\" +%n"); 105 } 106 } 107 } 108 109 static Pattern sbmap = Pattern.compile("0x(\\p{XDigit}++)\\s++U\\+(\\p{XDigit}++)(\\s++#.*)?"); 110 111 private static void genClass(String srcDir, String dstDir, 112 String template, 113 String clzName, 114 String csName, 115 String hisName, 116 String pkgName, 117 boolean isASCII) 118 throws Exception 119 { 120 StringBuilder b2cSB = new StringBuilder(); 121 StringBuilder b2cNRSB = new StringBuilder(); 122 StringBuilder c2bNRSB = new StringBuilder(); 123 124 char[] sb = new char[0x100]; 125 char[] c2bIndex = new char[0x100]; 126 int c2bOff = 0; 127 Arrays.fill(sb, UNMAPPABLE_DECODING); 128 Arrays.fill(c2bIndex, UNMAPPABLE_DECODING); 129 130 // (1)read in .map to parse all b->c entries 131 FileInputStream in = new FileInputStream( 132 new File(srcDir, clzName + ".map")); 133 Parser p = new Parser(in, sbmap); 134 Entry e = null; 135 136 while ((e = p.next()) != null) { 137 sb[e.bs] = (char)e.cp; 138 if (c2bIndex[e.cp>>8] == UNMAPPABLE_DECODING) { 139 c2bOff += 0x100; 140 c2bIndex[e.cp>>8] = 1; 141 } 142 } 143 144 Formatter fm = new Formatter(b2cSB); 145 fm.format("%n"); 146 147 // vm -server shows cc[byte + 128] access is much faster than 148 // cc[byte&0xff] so we output the upper segment first 149 toString(sb, 0x80, 0x100, fm, "+", true); 150 toString(sb, 0x00, 0x80, fm, ";", true); 151 fm.close(); 152 153 // (2)now the .nr file which includes "b->c" non-roundtrip entries 154 File f = new File(srcDir, clzName + ".nr"); 155 if (f.exists()) { 156 in = new FileInputStream(f); 157 fm = new Formatter(b2cNRSB); 158 p = new Parser(in, sbmap); 159 e = null; 160 161 fm.format("// remove non-roundtrip entries%n"); 162 fm.format(" b2cMap = b2cTable.toCharArray();%n"); 163 while ((e = p.next()) != null) { 164 fm.format(" b2cMap[%d] = UNMAPPABLE_DECODING;%n", 165 (e.bs>=0x80)?(e.bs-0x80):(e.bs+0x80)); 166 } 167 fm.close(); 168 } 169 170 // (3)finally the .c2b file which includes c->b non-roundtrip entries 171 f = new File(srcDir, clzName + ".c2b"); 172 if (f.exists()) { 173 in = new FileInputStream(f); 174 fm = new Formatter(c2bNRSB); 175 p = new Parser(in, sbmap); 176 e = null; 177 ArrayList<Entry> es = new ArrayList<Entry>(); 178 while ((e = p.next()) != null) { 179 if (c2bIndex[e.cp>>8] == UNMAPPABLE_DECODING) { 180 c2bOff += 0x100; 181 c2bIndex[e.cp>>8] = 1; 182 } 183 es.add(e); 184 } 185 fm.format("// non-roundtrip c2b only entries%n"); 186 if (es.size() < 100) { 187 fm.format(" c2bNR = new char[%d];%n", es.size() * 2); 188 int i = 0; 189 for (Entry entry: es) { 190 fm.format(" c2bNR[%d] = 0x%x; c2bNR[%d] = 0x%x;%n", 191 i++, entry.bs, i++, entry.cp); 192 } 193 } else { 194 char[] cc = new char[es.size() * 2]; 195 int i = 0; 196 for (Entry entry: es) { 197 cc[i++] = (char)entry.bs; 198 cc[i++] = (char)entry.cp; 199 } 200 fm.format(" c2bNR = (%n"); 201 toString(cc, 0, i, fm, ").toCharArray();", false); 202 } 203 fm.close(); 204 } 205 206 // (4)it's time to generate the source file 207 String b2c = b2cSB.toString(); 208 String b2cNR = b2cNRSB.toString(); 209 String c2bNR = c2bNRSB.toString(); 210 211 Scanner s = new Scanner(new File(srcDir, template)); 212 PrintStream out = new PrintStream(new FileOutputStream( 213 new File(dstDir, clzName + ".java"))); 214 215 while (s.hasNextLine()) { 216 String line = s.nextLine(); 217 int i = line.indexOf("$"); 218 if (i == -1) { 219 out.println(line); 220 continue; 221 } 222 if (line.indexOf("$PACKAGE$", i) != -1) { 223 line = line.replace("$PACKAGE$", pkgName); 224 } 225 if (line.indexOf("$NAME_CLZ$", i) != -1) { 226 line = line.replace("$NAME_CLZ$", clzName); 227 } 228 if (line.indexOf("$NAME_CS$", i) != -1) { 229 line = line.replace("$NAME_CS$", csName); 230 } 231 if (line.indexOf("$NAME_ALIASES$", i) != -1) { 232 if ("sun.nio.cs".equals(pkgName)) 233 line = line.replace("$NAME_ALIASES$", 234 "StandardCharsets.aliases_" + clzName); 235 else 236 line = line.replace("$NAME_ALIASES$", 237 "ExtendedCharsets.aliasesFor(\"" + csName + "\")"); 238 } 239 if (line.indexOf("$NAME_HIS$", i) != -1) { 240 line = line.replace("$NAME_HIS$", hisName); 241 } 242 if (line.indexOf("$CONTAINS$", i) != -1) { 243 if (isASCII) 244 line = " return ((cs.name().equals(\"US-ASCII\")) || (cs instanceof " + clzName + "));"; 245 else 246 line = " return (cs instanceof " + clzName + ");"; 247 } 248 if (line.indexOf("$B2CTABLE$") != -1) { 249 line = line.replace("$B2CTABLE$", b2c); 250 } 251 if (line.indexOf("$C2BLENGTH$") != -1) { 252 line = line.replace("$C2BLENGTH$", "0x" + Integer.toString(c2bOff, 16)); 253 } 254 if (line.indexOf("$NONROUNDTRIP_B2C$") != -1) { 255 if (b2cNR.length() == 0) 256 continue; 257 line = line.replace("$NONROUNDTRIP_B2C$", b2cNR); 258 } 259 260 if (line.indexOf("$NONROUNDTRIP_C2B$") != -1) { 261 if (c2bNR.length() == 0) 262 continue; 263 line = line.replace("$NONROUNDTRIP_C2B$", c2bNR); 264 } 265 out.println(line); 266 } 267 out.close(); 268 } 269 }