1 /*
   2  * Copyright (c) 2009, 2017, 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         int COPYRIGHT_SRC  = 7;
  45 
  46         if (args.length < 3 ) {
  47             System.out.println("Usage: java -jar charsetmapping.jar src dst spiType charsets os [template]");
  48             System.exit(1);
  49         }
  50         boolean isStandard = "stdcs".equals(args[TYPE]);
  51         boolean isExtended = "extcs".equals(args[TYPE]);
  52         if (isStandard || isExtended) {
  53             LinkedHashMap<String, Charset> charsets = getCharsets(
  54                 new File(args[SRC_DIR], args[CHARSETS]));
  55             String[] osStdcs = getOSStdCSList(new File(args[SRC_DIR], args[OS]));
  56             boolean hasBig5_HKSCS = false;
  57             boolean hasMS950_HKSCS = false;
  58             boolean hasMS950_HKSCS_XP = false;
  59             boolean hasEUC_TW = false;
  60             for (String name : osStdcs) {
  61                 Charset cs = charsets.get(name);
  62                 if (cs != null) {
  63                     cs.pkgName = "sun.nio.cs";
  64                 }
  65                 if (name.equals("Big5_HKSCS")) {
  66                     hasBig5_HKSCS = true;
  67                 } else if (name.equals("MS950_HKSCS")) {
  68                     hasMS950_HKSCS = true;
  69                 } else if (name.equals("MS950_HKSCS_XP")) {
  70                     hasMS950_HKSCS_XP = true;
  71                 } else if (name.equals("EUC_TW")) {
  72                     hasEUC_TW = true;
  73                 }
  74             }
  75             for (Charset cs : charsets.values()) {
  76                 if (isStandard && cs.pkgName.equals("sun.nio.cs.ext") ||
  77                     isExtended && cs.pkgName.equals("sun.nio.cs")) {
  78                     continue;
  79                 }
  80                 verbose(cs);
  81                 switch (cs.type) {
  82                 case "template":
  83                     SRC.genClass(cs, args[EXT_SRC], args[DST_DIR]);
  84                     break;
  85                 case "sbcs":
  86                     SBCS.genClass(cs, args[SRC_DIR], args[DST_DIR],
  87                                   "SingleByte-X.java.template");
  88                     break;
  89                 case "source":
  90                     break;                   // source file, do nothing
  91                 default:                     // dbcs
  92                     DBCS.genClass("dbcs".equals(cs.type) ?
  93                                       "" :  "_" + cs.type.toUpperCase(Locale.ENGLISH),
  94                                   cs, args[SRC_DIR], args[DST_DIR],
  95                                   "DoubleByte-X.java.template");
  96                 }
  97             }
  98             // provider StandardCharsets.java / ExtendedCharsets.java
  99             SPI.genClass(args[TYPE], charsets,
 100                          args[SRC_DIR], args[DST_DIR],
 101                          args[TEMPLATE],
 102                          args[OS].endsWith("windows") ? "windows" : "unix");
 103 
 104             // HKSCSMapping(2008).java goes std if one of Big5_HKSCS MS950_HKSCS
 105             // is in std
 106             if (isStandard && (hasBig5_HKSCS || hasMS950_HKSCS) ||
 107                 isExtended && !(hasBig5_HKSCS  || hasMS950_HKSCS)) {
 108                 HKSCS.genClass2008(args[SRC_DIR], args[DST_DIR],
 109                                    isStandard ? "sun.nio.cs" : "sun.nio.cs.ext",
 110                                    new File(args[COPYRIGHT_SRC], "HKSCS.java"));
 111             }
 112             // HKSCS_XPMapping.java goes together with MS950XP_HKSCS
 113             if (isStandard && hasMS950_HKSCS_XP || isExtended && !hasMS950_HKSCS_XP) {
 114                 HKSCS.genClassXP(args[SRC_DIR], args[DST_DIR],
 115                                  isStandard ? "sun.nio.cs" : "sun.nio.cs.ext",
 116                                  new File(args[COPYRIGHT_SRC], "HKSCS.java"));
 117             }
 118             if (isStandard && hasEUC_TW) {
 119                 EUC_TW.genClass("sun.nio.cs", args);
 120             }
 121             if (!isStandard && !hasEUC_TW) {
 122                 EUC_TW.genClass("sun.nio.cs.ext", args);
 123             }
 124         } else if ("sjis0213".equals(args[TYPE])) {
 125             JIS0213.genClass(args);
 126         } else if ("hkscs".equals(args[TYPE])) {
 127             HKSCS.genClass2001(args);
 128         }
 129     }
 130 
 131     private static LinkedHashMap<String, Charset> getCharsets(File cslist)
 132         throws Throwable
 133     {
 134         LinkedHashMap<String, Charset> charsets = new LinkedHashMap<>();
 135         try (Scanner s = new Scanner(cslist)) {
 136             Charset cs = null;
 137             ArrayList<String> names = new ArrayList<>();
 138             while (s.hasNextLine()) {
 139                 String line = s.nextLine();
 140                 if (line.startsWith("#") || line.length() == 0) {
 141                     continue;
 142                 }
 143                 String[] tokens = line.split("\\s+");
 144                 if (tokens.length < 2) {
 145                     continue;
 146                 }
 147                 if ("charset".equals(tokens[0])) {
 148                     if (cs != null) {
 149                         cs.aliases = names.toArray(new String[names.size()]);
 150                         charsets.put(cs.clzName, cs);
 151                         cs = null;
 152                         names.clear();
 153                     }
 154                     if (tokens.length < 3) {
 155                         throw new RuntimeException("Error: incorrect charset line [" + line + "]");
 156                     }
 157                     if ((cs = charsets.get(tokens[2])) != null) {
 158                         throw new RuntimeException("Error: deplicate charset line [" + line + "]");
 159                     }
 160                     cs = new Charset();
 161                     cs.csName = tokens[1];
 162                     cs.clzName = tokens[2];
 163                 } else {
 164                     String key = tokens[1];           // leading empty str
 165                     switch (key) {
 166                     case "alias":
 167                         if (tokens.length < 3) {
 168                             throw new RuntimeException("Error: incorrect alias line [" + line + "]");
 169                         } else if (names != null) {
 170                             names.add(tokens[2]);     // ALIAS_NAME
 171                         }
 172                         break;
 173                     case "package":
 174                         cs.pkgName = tokens[2];
 175                         break;
 176                     case "type":
 177                         cs.type = tokens[2];
 178                         break;
 179                     case "os":
 180                         cs.os = tokens[2];
 181                         break;
 182                     case "hisname":
 183                         cs.hisName = tokens[2];
 184                         break;
 185                     case "ascii":
 186                         cs.isASCII = Boolean.parseBoolean(tokens[2]);
 187                         break;
 188                     case "minmax":
 189                         cs.b1Min = toInteger(tokens[2]);
 190                         cs.b1Max = toInteger(tokens[3]);
 191                         cs.b2Min = toInteger(tokens[4]);
 192                         cs.b2Max = toInteger(tokens[5]);
 193                         break;
 194                     case "internal":
 195                         cs.isInternal = Boolean.parseBoolean(tokens[2]);
 196                         break;
 197                     default:  // ignore
 198                     }
 199                 }
 200             }
 201             if (cs != null) {
 202                 cs.aliases = names.toArray(new String[names.size()]);
 203                 charsets.put(cs.clzName, cs);
 204             }
 205         }
 206         return charsets;
 207     }
 208 
 209     private static String[] getOSStdCSList(File stdcsos) throws Throwable
 210     {
 211         ArrayList<String> names = new ArrayList<>();
 212         if (stdcsos.exists()) {
 213             try (Scanner s = new Scanner(stdcsos)) {
 214                 while (s.hasNextLine()) {
 215                     String line = s.nextLine();
 216                     int i = line.indexOf('#');
 217                     if (i != -1) {
 218                         line = line.substring(0, i);
 219                     }
 220                     line = line.trim();
 221                     if (line.length() != 0) {
 222                         names.add(line);
 223                     }
 224                 }
 225             }
 226         }
 227         return names.toArray(new String[names.size()]);
 228     }
 229 
 230     static void verbose(Charset cs) {
 231          System.out.printf("%s, %s, %s, %s, %s  %b%n",
 232                            cs.clzName, cs.csName, cs.hisName, cs.pkgName, cs.type, cs.isASCII);
 233     }
 234 
 235     static int toInteger(String s) {
 236         return (s.startsWith("0x") || s.startsWith("0X"))
 237                ? Integer.valueOf(s.substring(2), 16)
 238                : Integer.valueOf(s);
 239     }
 240 }