1 /*
   2  * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package build.tools.charsetmapping;
  27 
  28 import java.io.*;
  29 import java.util.ArrayList;
  30 import java.util.Scanner;
  31 import java.util.LinkedHashMap;
  32 import java.util.Locale;
  33 
  34 public class Main {
  35 
  36     public static void main(String args[]) throws Throwable {
  37         int SRC_DIR  = 0;
  38         int DST_DIR  = 1;
  39         int TYPE     = 2;
  40         int CHARSETS = 3;
  41         int OS       = 4;
  42         int TEMPLATE = 5;
  43         int EXT_SRC  = 6;
  44 
  45         if (args.length < 3 ) {
  46             System.out.println("Usage: java -jar charsetmapping.jar src dst spiType charsets os [template]");
  47             System.exit(1);
  48         }
  49         boolean isStandard = "stdcs".equals(args[TYPE]);
  50         boolean isExtended = "extcs".equals(args[TYPE]);
  51         if (isStandard || isExtended) {
  52             LinkedHashMap<String, Charset> charsets = getCharsets(
  53                 new File(args[SRC_DIR], args[CHARSETS]));
  54             String[] osStdcs = getOSStdCSList(new File(args[SRC_DIR], args[OS]));
  55             boolean hasBig5_HKSCS = false;
  56             boolean hasMS950_HKSCS_XP = false;
  57             for (String name : osStdcs) {
  58                 Charset cs = charsets.get(name);
  59                 if (cs != null) {
  60                     cs.pkgName = "sun.nio.cs";
  61                 }
  62                 if (name.equals("Big5_HKSCS")) {
  63                     hasBig5_HKSCS = true;
  64                 } else if (name.equals("MS950_HKSCS_XP")) {
  65                     hasMS950_HKSCS_XP = true;
  66                 }
  67             }
  68             for (Charset cs : charsets.values()) {
  69                 if (isStandard && cs.pkgName.equals("sun.nio.cs.ext") ||
  70                     isExtended && cs.pkgName.equals("sun.nio.cs")) {
  71                     continue;
  72                 }
  73                 verbose(cs);
  74                 switch (cs.type) {
  75                 case "template":
  76                     SRC.genClass(cs, args[EXT_SRC], args[DST_DIR]);
  77                     break;
  78                 case "sbcs":
  79                     SBCS.genClass(cs, args[SRC_DIR], args[DST_DIR],
  80                                   "SingleByte-X.java.template");
  81                     break;
  82                 case "source":
  83                     break;                   // source file, do nothing
  84                 default:                     // dbcs
  85                     DBCS.genClass("dbcs".equals(cs.type) ?
  86                                       "" :  "_" + cs.type.toUpperCase(Locale.ENGLISH),
  87                                   cs, args[SRC_DIR], args[DST_DIR],
  88                                   "DoubleByte-X.java.template");
  89                 }
  90             }
  91             // provider StandardCharsets.java / ExtendedCharsets.java
  92             SPI.genClass(args[TYPE], charsets, args[SRC_DIR], args[DST_DIR], args[TEMPLATE]);
  93 
  94             // HKSCSMapping2008/XP.java goes together with Big5/MS950XP_HKSCS
  95             if (isStandard && hasBig5_HKSCS || isExtended && !hasBig5_HKSCS) {
  96                 HKSCS.genClass2008(args[SRC_DIR], args[DST_DIR],
  97                                    isStandard ? "sun.nio.cs" : "sun.nio.cs.ext");
  98             }
  99             if (isStandard && hasMS950_HKSCS_XP || isExtended && !hasMS950_HKSCS_XP) {
 100                 HKSCS.genClassXP(args[SRC_DIR], args[DST_DIR],
 101                                  isStandard ? "sun.nio.cs" : "sun.nio.cs.ext");
 102             }
 103         } else if ("euctw".equals(args[TYPE])) {
 104             EUC_TW.genClass(args);
 105         } else if ("sjis0213".equals(args[TYPE])) {
 106             JIS0213.genClass(args);
 107         } else if ("hkscs".equals(args[TYPE])) {
 108             HKSCS.genClass2001(args);
 109         }
 110     }
 111 
 112     private static LinkedHashMap<String, Charset> getCharsets(File cslist)
 113         throws Throwable
 114     {
 115         LinkedHashMap<String, Charset> charsets = new LinkedHashMap<>();
 116         try (Scanner s = new Scanner(cslist)) {
 117             Charset cs = null;
 118             ArrayList<String> names = new ArrayList<>();
 119             while (s.hasNextLine()) {
 120                 String line = s.nextLine();
 121                 if (line.startsWith("#") || line.length() == 0) {
 122                     continue;
 123                 }
 124                 String[] tokens = line.split("\\s+");
 125                 if (tokens.length < 2) {
 126                     continue;
 127                 }
 128                 if ("charset".equals(tokens[0])) {
 129                     if (cs != null) {
 130                         cs.aliases = names.toArray(new String[names.size()]);
 131                         charsets.put(cs.clzName, cs);
 132                         cs = null;
 133                         names.clear();
 134                     }
 135                     if (tokens.length < 3) {
 136                         throw new RuntimeException("Error: incorrect charset line [" + line + "]");
 137                     }
 138                     if ((cs = charsets.get(tokens[2])) != null) {
 139                         throw new RuntimeException("Error: deplicate charset line [" + line + "]");
 140                     }
 141                     cs = new Charset();
 142                     cs.csName = tokens[1];
 143                     cs.clzName = tokens[2];
 144                 } else {
 145                     String key = tokens[1];           // leading empty str
 146                     switch (key) {
 147                     case "alias":
 148                         if (tokens.length < 3) {
 149                             throw new RuntimeException("Error: incorrect alias line [" + line + "]");
 150                         } else if (names != null) {
 151                             names.add(tokens[2]);     // ALIAS_NAME
 152                         }
 153                         break;
 154                     case "package":
 155                         cs.pkgName = tokens[2];
 156                         break;
 157                     case "type":
 158                         cs.type = tokens[2];
 159                         break;
 160                     case "hisname":
 161                         cs.hisName = tokens[2];
 162                         break;
 163                     case "ascii":
 164                         cs.isASCII = Boolean.parseBoolean(tokens[2]);
 165                         break;
 166                     case "minmax":
 167                         cs.b1Min = toInteger(tokens[2]);
 168                         cs.b1Max = toInteger(tokens[3]);
 169                         cs.b2Min = toInteger(tokens[4]);
 170                         cs.b2Max = toInteger(tokens[5]);
 171                         break;
 172                     case "internal":
 173                         cs.isInternal = Boolean.parseBoolean(tokens[2]);
 174                         break;
 175                     default:  // ignore
 176                     }
 177                 }
 178             }
 179             if (cs != null) {
 180                 cs.aliases = names.toArray(new String[names.size()]);
 181                 charsets.put(cs.clzName, cs);
 182             }
 183         }
 184         return charsets;
 185     }
 186 
 187     private static String[] getOSStdCSList(File stdcsos) throws Throwable
 188     {
 189         ArrayList<String> names = new ArrayList<>();
 190         if (stdcsos.exists()) {
 191             try (Scanner s = new Scanner(stdcsos)) {
 192                 while (s.hasNextLine()) {
 193                     String line = s.nextLine();
 194                     int i = line.indexOf('#');
 195                     if (i != -1) {
 196                         line = line.substring(0, i);
 197                     }
 198                     line = line.trim();
 199                     if (line.length() != 0) {
 200                         names.add(line);
 201                     }
 202                 }
 203             }
 204         }
 205         return names.toArray(new String[names.size()]);
 206     }
 207 
 208     static void verbose(Charset cs) {
 209          System.err.printf("%s, %s, %s, %s, %s  %b%n",
 210                            cs.clzName, cs.csName, cs.hisName, cs.pkgName, cs.type, cs.isASCII);
 211     }
 212 
 213     static int toInteger(String s) {
 214         return (s.startsWith("0x") || s.startsWith("0X"))
 215                ? Integer.valueOf(s.substring(2), 16)
 216                : Integer.valueOf(s);
 217     }
 218 }