1 /*
   2  * Copyright (c) 2012, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 import java.io.*;
  25 import java.nio.charset.*;
  26 import java.nio.file.*;
  27 import java.util.*;
  28 
  29 public class EquivMapsGenerator {
  30 
  31     /*
  32      * IANA Language Subtag Registry file downloaded from
  33      *     http://www.iana.org/assignments/language-subtag-registry
  34      */
  35     private static final String DEFAULT_LSR_FILE =
  36         "language-subtag-registry.txt";
  37 
  38     private static boolean verbose = false;
  39 
  40     public static void main(String[] args) throws Exception {
  41         String fileLSR = DEFAULT_LSR_FILE;
  42 
  43         for (int i = 0; i < args.length; i++) {
  44             String s = args[i];
  45             if (s.equals("-lsr")) {
  46                 fileLSR = args[++i];
  47             } else if (s.equals("-verbose")) {
  48                 verbose = true;
  49             }
  50         }
  51 
  52         readLSRfile(fileLSR);
  53         generateEquivalentMap();
  54         generateSourceCode();
  55     }
  56 
  57     private static String LSRrevisionDate;
  58     private static Map<String, StringBuilder> initialLanguageMap =
  59         new TreeMap<>();
  60     private static Map<String, StringBuilder> initialRegionVariantMap =
  61         new TreeMap<>();
  62 
  63     private static Map<String, String> sortedLanguageMap1 = new TreeMap<>();
  64     private static Map<String, String[]> sortedLanguageMap2 = new TreeMap<>();
  65     private static Map<String, String> sortedRegionVariantMap =
  66         new TreeMap<>();
  67 
  68     private static void readLSRfile(String filename) throws Exception {
  69         String type = null;
  70         String tag = null;
  71         String preferred = null;
  72         int mappingNum = 0;
  73 
  74         for (String line : Files.readAllLines(Paths.get(filename),
  75                                               Charset.forName("UTF-8"))) {
  76             line = line.toLowerCase();
  77             int index = line.indexOf(' ')+1;
  78             if (line.startsWith("file-date:")) {
  79                 LSRrevisionDate = line.substring(index);
  80                 if (verbose) {
  81                     System.out.println("LSR revision date=" + LSRrevisionDate);
  82                 }
  83             } else if (line.startsWith("type:")) {
  84                 type = line.substring(index);
  85             } else if (line.startsWith("tag:") || line.startsWith("subtag:")) {
  86                 tag = line.substring(index);
  87             } else if (line.startsWith("preferred-value:")
  88                        && !type.equals("extlang")) {
  89                 preferred = line.substring(index);
  90                 mappingNum++;
  91                 processDeprecatedData(type, tag, preferred);
  92             } else if (line.equals("%%")) {
  93                 type = null;
  94                 tag = null;
  95                 preferred = null;
  96             }
  97         }
  98 
  99         if (verbose) {
 100             System.out.println("readLSRfile(" + filename + ")");
 101             System.out.println("  Total number of mapping=" + mappingNum);
 102             System.out.println("\n  Map for language. Size="
 103                 + initialLanguageMap.size());
 104 
 105             for (String key : initialLanguageMap.keySet()) {
 106                 System.out.println("    " + key + ": \""
 107                     + initialLanguageMap.get(key) + "\"");
 108             }
 109 
 110             System.out.println("\n  Map for region and variant. Size="
 111                 + initialRegionVariantMap.size());
 112 
 113             for (String key : initialRegionVariantMap.keySet()) {
 114                 System.out.println("    " + key + ": \""
 115                     + initialRegionVariantMap.get(key) + "\"");
 116             }
 117         }
 118     }
 119 
 120     private static void processDeprecatedData(String type,
 121                                               String tag,
 122                                               String preferred) {
 123         StringBuilder sb;
 124         if (type.equals("region") || type.equals("variant")) {
 125             if (!initialRegionVariantMap.containsKey(preferred)) {
 126                 sb = new StringBuilder("-");
 127                 sb.append(preferred);
 128                 sb.append(",-");
 129                 sb.append(tag);
 130                 initialRegionVariantMap.put("-"+preferred, sb);
 131             } else {
 132                 throw new RuntimeException("New case, need implementation."
 133                     + " A region/variant subtag \"" + preferred
 134                     + "\" is registered for more than one subtags.");
 135             }
 136         } else { // language, grandfahered, and redundant
 137             if (!initialLanguageMap.containsKey(preferred)) {
 138                 sb = new StringBuilder(preferred);
 139                 sb.append(',');
 140                 sb.append(tag);
 141                 initialLanguageMap.put(preferred, sb);
 142             } else {
 143                 sb = initialLanguageMap.get(preferred);
 144                 sb.append(',');
 145                 sb.append(tag);
 146                 initialLanguageMap.put(preferred, sb);
 147             }
 148         }
 149     }
 150 
 151     private static void generateEquivalentMap() {
 152         String[] subtags;
 153         for (String preferred : initialLanguageMap.keySet()) {
 154             subtags = initialLanguageMap.get(preferred).toString().split(",");
 155 
 156             if (subtags.length == 2) {
 157                 sortedLanguageMap1.put(subtags[0], subtags[1]);
 158                 sortedLanguageMap1.put(subtags[1], subtags[0]);
 159             } else if (subtags.length == 3) {
 160                 sortedLanguageMap2.put(subtags[0],
 161                                      new String[]{subtags[1], subtags[2]});
 162                 sortedLanguageMap2.put(subtags[1],
 163                                      new String[]{subtags[0], subtags[2]});
 164                 sortedLanguageMap2.put(subtags[2],
 165                                      new String[]{subtags[0], subtags[1]});
 166             } else {
 167                     throw new RuntimeException("New case, need implementation."
 168                         + " A language subtag \"" + preferred
 169                         + "\" is registered for more than two subtags. ");
 170             }
 171         }
 172 
 173         for (String preferred : initialRegionVariantMap.keySet()) {
 174             subtags =
 175                 initialRegionVariantMap.get(preferred).toString().split(",");
 176 
 177             sortedRegionVariantMap.put(subtags[0], subtags[1]);
 178             sortedRegionVariantMap.put(subtags[1], subtags[0]);
 179         }
 180 
 181         if (verbose) {
 182             System.out.println("generateEquivalentMap()");
 183             System.out.println("  \nSorted map for language subtags which have only one equivalent. Size="
 184                 + sortedLanguageMap1.size());
 185             for (String key : sortedLanguageMap1.keySet()) {
 186                 System.out.println("    " + key + ": \""
 187                     + sortedLanguageMap1.get(key) + "\"");
 188             }
 189 
 190             System.out.println("\n  Sorted map for language subtags which have multiple equivalents. Size="
 191                 + sortedLanguageMap2.size());
 192             for (String key : sortedLanguageMap2.keySet()) {
 193                 String[] s = sortedLanguageMap2.get(key);
 194                 System.out.println("    " + key + ": \""
 195                     + s[0] + "\", \"" + s[1] + "\"");
 196             }
 197 
 198             System.out.println("\n  Sorted map for region and variant subtags. Size="
 199                 + sortedRegionVariantMap.size());
 200             for (String key : sortedRegionVariantMap.keySet()) {
 201                 System.out.println("    " + key + ": \""
 202                     + sortedRegionVariantMap.get(key) + "\"");
 203             }
 204         }
 205         System.out.println();
 206     }
 207 
 208     private final static String headerText =
 209         "final class LocaleEquivalentMaps {\n\n"
 210         + "    static final Map<String, String> singleEquivMap;\n"
 211         + "    static final Map<String, String[]> multiEquivsMap;\n"
 212         + "    static final Map<String, String> regionVariantEquivMap;\n\n"
 213         + "    static {\n"
 214         + "        singleEquivMap = new HashMap<>();\n"
 215         + "        multiEquivsMap = new HashMap<>();\n"
 216         + "        regionVariantEquivMap = new HashMap<>();\n\n"
 217         + "        // This is an auto-generated file and should not be manually edited.\n";
 218 
 219     private final static String footerText =
 220         "    }\n\n"
 221         + "}";
 222 
 223     private static void generateSourceCode() {
 224         System.out.println(headerText
 225             + "        //   LSR Revision: " + LSRrevisionDate);
 226 
 227         for (String key : sortedLanguageMap1.keySet()) {
 228             String value = sortedLanguageMap1.get(key);
 229             System.out.println("        singleEquivMap.put(\""
 230                 + key + "\", \"" + value + "\");");
 231         }
 232         System.out.println();
 233         for (String key : sortedLanguageMap2.keySet()) {
 234             String[] values = sortedLanguageMap2.get(key);
 235             System.out.println("        multiEquivsMap.put(\""
 236                 + key + "\", new String[] {\"" + values[0] + "\", \""
 237                 + values[1] + "\"});");
 238         }
 239         System.out.println();
 240         for (String key : sortedRegionVariantMap.keySet()) {
 241             String value = sortedRegionVariantMap.get(key);
 242             System.out.println("        regionVariantEquivMap.put(\""
 243                 + key + "\", \"" + value + "\");");
 244         }
 245 
 246         System.out.println(footerText);
 247     }
 248 
 249 }