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