make/src/classes/build/tools/cldrconverter/Bundle.java

Print this page


   1 /*
   2  * Copyright (c) 2012, 2013, 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.cldrconverter;
  27 
  28 import java.util.ArrayList;
  29 import java.util.Arrays;
  30 import java.util.EnumSet;
  31 import java.util.HashMap;
  32 import java.util.Iterator;
  33 import java.util.List;
  34 import java.util.Map;

  35 
  36 class Bundle {
  37     static enum Type {
  38         LOCALENAMES, CURRENCYNAMES, TIMEZONENAMES, CALENDARDATA, FORMATDATA;
  39 
  40         static EnumSet<Type> ALL_TYPES = EnumSet.of(LOCALENAMES,
  41                                                     CURRENCYNAMES,
  42                                                     TIMEZONENAMES,
  43                                                     CALENDARDATA,
  44                                                     FORMATDATA);
  45     }
  46 
  47     private final static Map<String, Bundle> bundles = new HashMap<>();
  48 
  49     private final static String[] NUMBER_PATTERN_KEYS = {
  50         "NumberPatterns/decimal",
  51         "NumberPatterns/currency",
  52         "NumberPatterns/percent"
  53     };
  54 


  64         "NumberElements/permille",
  65         "NumberElements/infinity",
  66         "NumberElements/nan"
  67     };
  68 
  69     private final static String[] TIME_PATTERN_KEYS = {
  70         "DateTimePatterns/full-time",
  71         "DateTimePatterns/long-time",
  72         "DateTimePatterns/medium-time",
  73         "DateTimePatterns/short-time",
  74     };
  75 
  76     private final static String[] DATE_PATTERN_KEYS = {
  77         "DateTimePatterns/full-date",
  78         "DateTimePatterns/long-date",
  79         "DateTimePatterns/medium-date",
  80         "DateTimePatterns/short-date",
  81     };
  82 
  83     private final static String[] DATETIME_PATTERN_KEYS = {
  84         "DateTimePatterns/date-time"



  85     };
  86 
  87     private final static String[] ERA_KEYS = {
  88         "long.Eras",
  89         "Eras",
  90         "narrow.Eras"
  91     };
  92 
  93     // Keys for individual time zone names
  94     private final static String TZ_GEN_LONG_KEY = "timezone.displayname.generic.long";
  95     private final static String TZ_GEN_SHORT_KEY = "timezone.displayname.generic.short";
  96     private final static String TZ_STD_LONG_KEY = "timezone.displayname.standard.long";
  97     private final static String TZ_STD_SHORT_KEY = "timezone.displayname.standard.short";
  98     private final static String TZ_DST_LONG_KEY = "timezone.displayname.daylight.long";
  99     private final static String TZ_DST_SHORT_KEY = "timezone.displayname.daylight.short";
 100     private final static String[] ZONE_NAME_KEYS = {
 101         TZ_STD_LONG_KEY,
 102         TZ_STD_SHORT_KEY,
 103         TZ_DST_LONG_KEY,
 104         TZ_DST_SHORT_KEY,


 153         return bundleTypes;
 154     }
 155 
 156     String getCurrencies() {
 157         return currencies;
 158     }
 159 
 160     /**
 161      * Generate a map that contains all the data that should be
 162      * visible for the bundle's locale
 163      */
 164     Map<String, Object> getTargetMap() throws Exception {
 165         String[] cldrBundles = getCLDRPath().split(",");
 166 
 167         // myMap contains resources for id.
 168         Map<String, Object> myMap = new HashMap<>();
 169         int index;
 170         for (index = 0; index < cldrBundles.length; index++) {
 171             if (cldrBundles[index].equals(id)) {
 172                 myMap.putAll(CLDRConverter.getCLDRBundle(cldrBundles[index]));

 173                 break;
 174             }
 175         }
 176 
 177         // parentsMap contains resources from id's parents.
 178         Map<String, Object> parentsMap = new HashMap<>();
 179         for (int i = cldrBundles.length - 1; i > index; i--) {
 180             if (!("no".equals(cldrBundles[i]) || cldrBundles[i].startsWith("no_"))) {
 181                 parentsMap.putAll(CLDRConverter.getCLDRBundle(cldrBundles[i]));

 182             }
 183         }
 184         // Duplicate myMap as parentsMap for "root" so that the
 185         // fallback works. This is a huck, though.
 186         if ("root".equals(cldrBundles[0])) {
 187             assert parentsMap.isEmpty();
 188             parentsMap.putAll(myMap);
 189         }
 190 
 191         // merge individual strings into arrays
 192 
 193         // if myMap has any of the NumberPatterns members
 194         for (String k : NUMBER_PATTERN_KEYS) {
 195             if (myMap.containsKey(k)) {
 196                 String[] numberPatterns = new String[NUMBER_PATTERN_KEYS.length];
 197                 for (int i = 0; i < NUMBER_PATTERN_KEYS.length; i++) {
 198                     String key = NUMBER_PATTERN_KEYS[i];
 199                     String value = (String) myMap.remove(key);
 200                     if (value == null) {
 201                         value = (String) parentsMap.remove(key);
 202                     }
 203                     if (value.length() == 0) {
 204                         CLDRConverter.warning("empty pattern for " + key);
 205                     }


 353                             for (int i = 0; i < names.length; i++) {
 354                                 if (names[i] == null) {
 355                                     names[i] = enNames[i];
 356                                 }
 357                             }
 358                         }
 359                         // If there are still nulls, give up names.
 360                         if (hasNulls(names)) {
 361                             names = null;
 362                         }
 363                     }
 364                 }
 365                 // replace the Map with the array
 366                 if (names != null) {
 367                     myMap.put(key, names);
 368                 } else {
 369                     it.remove();
 370                 }
 371             }
 372         }











 373         return myMap;
 374     }
 375 
 376     private void handleMultipleInheritance(Map<String, Object> map, Map<String, Object> parents, String key) {
 377         String formatKey = key + "/format";
 378         Object format = map.get(formatKey);
 379         if (format != null) {
 380             map.remove(formatKey);
 381             map.put(key, format);
 382             if (fillInElements(parents, formatKey, format)) {
 383                 map.remove(key);
 384             }
 385         }
 386         String standaloneKey = key + "/stand-alone";
 387         Object standalone = map.get(standaloneKey);
 388         if (standalone != null) {
 389             map.remove(standaloneKey);
 390             String realKey = key;
 391             if (format != null) {
 392                 realKey = "standalone." + key;


 489                 int len = patternKeys.length;
 490                 List<String> rawPatterns = new ArrayList<>(len);
 491                 List<String> patterns = new ArrayList<>(len);
 492                 for (int i = 0; i < len; i++) {
 493                     String key = calendarPrefix + patternKeys[i];
 494                     String pattern = (String) myMap.remove(key);
 495                     if (pattern == null) {
 496                         pattern = (String) parentsMap.remove(key);
 497                     }
 498                     rawPatterns.add(i, pattern);
 499                     if (pattern != null) {
 500                         patterns.add(i, translateDateFormatLetters(calendarType, pattern));
 501                     } else {
 502                         patterns.add(i, null);
 503                     }
 504                 }
 505                 // If patterns is empty or has any nulls, discard patterns.
 506                 if (patterns.isEmpty()) {
 507                     return;
 508                 }
 509                 for (String p : patterns) {
 510                     if (p == null) {
 511                         return;
 512                     }
 513                 }
 514                 String key = calendarPrefix + name;
 515                 if (!rawPatterns.equals(patterns)) {
 516                     myMap.put("java.time." + key, rawPatterns.toArray(new String[len]));
 517                 }
 518                 myMap.put(key, patterns.toArray(new String[len]));
 519                 break;
 520             }
 521         }
 522     }
 523 
 524     private String translateDateFormatLetters(CalendarType calendarType, String cldrFormat) {
 525         String pattern = cldrFormat;
 526         int length = pattern.length();
 527         boolean inQuote = false;
 528         StringBuilder jrePattern = new StringBuilder(length);
 529         int count = 0;
 530         char lastLetter = 0;
 531 
 532         for (int i = 0; i < length; i++) {
 533             char c = pattern.charAt(i);


 613         fillInAbbrs(TZ_STD_LONG_KEY, TZ_STD_SHORT_KEY, map);
 614         fillInAbbrs(TZ_DST_LONG_KEY, TZ_DST_SHORT_KEY, map);
 615         fillInAbbrs(TZ_GEN_LONG_KEY, TZ_GEN_SHORT_KEY, map);
 616 
 617         // If the standard std is "Standard Time" and daylight std is "Summer Time",
 618         // replace the standard std with the generic std to avoid using
 619         // the same abbrivation except for Australia time zone names.
 620         String std = map.get(TZ_STD_SHORT_KEY);
 621         String dst = map.get(TZ_DST_SHORT_KEY);
 622         String gen = map.get(TZ_GEN_SHORT_KEY);
 623         if (std != null) {
 624             if (dst == null) {
 625                 // if dst is null, create long and short names from the standard
 626                 // std. ("Something Standard Time" to "Something Daylight Time",
 627                 // or "Something Time" to "Something Summer Time")
 628                 String name = map.get(TZ_STD_LONG_KEY);
 629                 if (name != null) {
 630                     if (name.contains("Standard Time")) {
 631                         name = name.replace("Standard Time", "Daylight Time");
 632                     } else if (name.endsWith("Mean Time")) {

 633                         name = name.replace("Mean Time", "Summer Time");

 634                     } else if (name.endsWith(" Time")) {
 635                         name = name.replace(" Time", " Summer Time");
 636                     }
 637                     map.put(TZ_DST_LONG_KEY, name);
 638                     fillInAbbrs(TZ_DST_LONG_KEY, TZ_DST_SHORT_KEY, map);
 639                 }
 640             }
 641             if (gen  == null) {
 642                 String name = map.get(TZ_STD_LONG_KEY);
 643                 if (name != null) {
 644                     if (name.endsWith("Standard Time")) {
 645                         name = name.replace("Standard Time", "Time");
 646                     } else if (name.endsWith("Mean Time")) {

 647                         name = name.replace("Mean Time", "Time");
 648                     }

 649                     map.put(TZ_GEN_LONG_KEY, name);
 650                     fillInAbbrs(TZ_GEN_LONG_KEY, TZ_GEN_SHORT_KEY, map);
 651                 }
 652             }
 653         }
 654     }
 655 
 656     private void fillInAbbrs(String longKey, String shortKey, Map<String, String> map) {
 657         String abbr = map.get(shortKey);
 658         if (abbr == null) {
 659             String name = map.get(longKey);
 660             if (name != null) {
 661                 abbr = toAbbr(name);
 662                 if (abbr != null) {
 663                     map.put(shortKey, abbr);
 664                 }
 665             }
 666         }
 667     }
 668 


 695             break;
 696 
 697         // TODO: support 'c' and 'e' in JRE SimpleDateFormat
 698         // Use 'u' and 'E' for now.
 699         case 'c':
 700         case 'e':
 701             switch (count) {
 702             case 1:
 703                 sb.append('u');
 704                 break;
 705             case 3:
 706             case 4:
 707                 appendN('E', count, sb);
 708                 break;
 709             case 5:
 710                 appendN('E', 3, sb);
 711                 break;
 712             }
 713             break;
 714 









 715         case 'v':
 716         case 'V':
 717             appendN('z', count, sb);
 718             break;
 719 
 720         case 'Z':
 721             if (count == 4 || count == 5) {
 722                 sb.append("XXX");
 723             }
 724             break;
 725 
 726         case 'u':
 727         case 'U':
 728         case 'q':
 729         case 'Q':
 730         case 'l':
 731         case 'g':
 732         case 'j':
 733         case 'A':
 734             throw new InternalError(String.format("Unsupported letter: '%c', count=%d%n",
 735                                                   cldrLetter, count));
 736         default:
 737             appendN(cldrLetter, count, sb);
 738             break;
 739         }
 740     }
 741 
 742     private void appendN(char c, int n, StringBuilder sb) {
 743         for (int i = 0; i < n; i++) {
 744             sb.append(c);
 745         }
 746     }
 747 
 748     private static boolean hasNulls(Object[] array) {
 749         for (int i = 0; i < array.length; i++) {
 750             if (array[i] == null) {
 751                 return true;
 752             }
 753         }
 754         return false;
 755     }
   1 /*
   2  * Copyright (c) 2012, 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.cldrconverter;
  27 
  28 import java.util.ArrayList;
  29 import java.util.Arrays;
  30 import java.util.EnumSet;
  31 import java.util.HashMap;
  32 import java.util.Iterator;
  33 import java.util.List;
  34 import java.util.Map;
  35 import java.util.Objects;
  36 
  37 class Bundle {
  38     static enum Type {
  39         LOCALENAMES, CURRENCYNAMES, TIMEZONENAMES, CALENDARDATA, FORMATDATA;
  40 
  41         static EnumSet<Type> ALL_TYPES = EnumSet.of(LOCALENAMES,
  42                                                     CURRENCYNAMES,
  43                                                     TIMEZONENAMES,
  44                                                     CALENDARDATA,
  45                                                     FORMATDATA);
  46     }
  47 
  48     private final static Map<String, Bundle> bundles = new HashMap<>();
  49 
  50     private final static String[] NUMBER_PATTERN_KEYS = {
  51         "NumberPatterns/decimal",
  52         "NumberPatterns/currency",
  53         "NumberPatterns/percent"
  54     };
  55 


  65         "NumberElements/permille",
  66         "NumberElements/infinity",
  67         "NumberElements/nan"
  68     };
  69 
  70     private final static String[] TIME_PATTERN_KEYS = {
  71         "DateTimePatterns/full-time",
  72         "DateTimePatterns/long-time",
  73         "DateTimePatterns/medium-time",
  74         "DateTimePatterns/short-time",
  75     };
  76 
  77     private final static String[] DATE_PATTERN_KEYS = {
  78         "DateTimePatterns/full-date",
  79         "DateTimePatterns/long-date",
  80         "DateTimePatterns/medium-date",
  81         "DateTimePatterns/short-date",
  82     };
  83 
  84     private final static String[] DATETIME_PATTERN_KEYS = {
  85         "DateTimePatterns/full-dateTime",
  86         "DateTimePatterns/long-dateTime",
  87         "DateTimePatterns/medium-dateTime",
  88         "DateTimePatterns/short-dateTime",
  89     };
  90 
  91     private final static String[] ERA_KEYS = {
  92         "long.Eras",
  93         "Eras",
  94         "narrow.Eras"
  95     };
  96 
  97     // Keys for individual time zone names
  98     private final static String TZ_GEN_LONG_KEY = "timezone.displayname.generic.long";
  99     private final static String TZ_GEN_SHORT_KEY = "timezone.displayname.generic.short";
 100     private final static String TZ_STD_LONG_KEY = "timezone.displayname.standard.long";
 101     private final static String TZ_STD_SHORT_KEY = "timezone.displayname.standard.short";
 102     private final static String TZ_DST_LONG_KEY = "timezone.displayname.daylight.long";
 103     private final static String TZ_DST_SHORT_KEY = "timezone.displayname.daylight.short";
 104     private final static String[] ZONE_NAME_KEYS = {
 105         TZ_STD_LONG_KEY,
 106         TZ_STD_SHORT_KEY,
 107         TZ_DST_LONG_KEY,
 108         TZ_DST_SHORT_KEY,


 157         return bundleTypes;
 158     }
 159 
 160     String getCurrencies() {
 161         return currencies;
 162     }
 163 
 164     /**
 165      * Generate a map that contains all the data that should be
 166      * visible for the bundle's locale
 167      */
 168     Map<String, Object> getTargetMap() throws Exception {
 169         String[] cldrBundles = getCLDRPath().split(",");
 170 
 171         // myMap contains resources for id.
 172         Map<String, Object> myMap = new HashMap<>();
 173         int index;
 174         for (index = 0; index < cldrBundles.length; index++) {
 175             if (cldrBundles[index].equals(id)) {
 176                 myMap.putAll(CLDRConverter.getCLDRBundle(cldrBundles[index]));
 177                 CLDRConverter.handleAliases(myMap);
 178                 break;
 179             }
 180         }
 181 
 182         // parentsMap contains resources from id's parents.
 183         Map<String, Object> parentsMap = new HashMap<>();
 184         for (int i = cldrBundles.length - 1; i > index; i--) {
 185             if (!("no".equals(cldrBundles[i]) || cldrBundles[i].startsWith("no_"))) {
 186                 parentsMap.putAll(CLDRConverter.getCLDRBundle(cldrBundles[i]));
 187                 CLDRConverter.handleAliases(parentsMap);
 188             }
 189         }
 190         // Duplicate myMap as parentsMap for "root" so that the
 191         // fallback works. This is a hack, though.
 192         if ("root".equals(cldrBundles[0])) {
 193             assert parentsMap.isEmpty();
 194             parentsMap.putAll(myMap);
 195         }
 196 
 197         // merge individual strings into arrays
 198 
 199         // if myMap has any of the NumberPatterns members
 200         for (String k : NUMBER_PATTERN_KEYS) {
 201             if (myMap.containsKey(k)) {
 202                 String[] numberPatterns = new String[NUMBER_PATTERN_KEYS.length];
 203                 for (int i = 0; i < NUMBER_PATTERN_KEYS.length; i++) {
 204                     String key = NUMBER_PATTERN_KEYS[i];
 205                     String value = (String) myMap.remove(key);
 206                     if (value == null) {
 207                         value = (String) parentsMap.remove(key);
 208                     }
 209                     if (value.length() == 0) {
 210                         CLDRConverter.warning("empty pattern for " + key);
 211                     }


 359                             for (int i = 0; i < names.length; i++) {
 360                                 if (names[i] == null) {
 361                                     names[i] = enNames[i];
 362                                 }
 363                             }
 364                         }
 365                         // If there are still nulls, give up names.
 366                         if (hasNulls(names)) {
 367                             names = null;
 368                         }
 369                     }
 370                 }
 371                 // replace the Map with the array
 372                 if (names != null) {
 373                     myMap.put(key, names);
 374                 } else {
 375                     it.remove();
 376                 }
 377             }
 378         }
 379 
 380         // Remove all duplicates
 381         if (Objects.nonNull(parentsMap)) {
 382             for (Iterator<String> it = myMap.keySet().iterator(); it.hasNext();) {
 383                 String key = it.next();
 384                 if (Objects.deepEquals(parentsMap.get(key), myMap.get(key))) {
 385                     it.remove();
 386                 }
 387             }
 388         }
 389 
 390         return myMap;
 391     }
 392 
 393     private void handleMultipleInheritance(Map<String, Object> map, Map<String, Object> parents, String key) {
 394         String formatKey = key + "/format";
 395         Object format = map.get(formatKey);
 396         if (format != null) {
 397             map.remove(formatKey);
 398             map.put(key, format);
 399             if (fillInElements(parents, formatKey, format)) {
 400                 map.remove(key);
 401             }
 402         }
 403         String standaloneKey = key + "/stand-alone";
 404         Object standalone = map.get(standaloneKey);
 405         if (standalone != null) {
 406             map.remove(standaloneKey);
 407             String realKey = key;
 408             if (format != null) {
 409                 realKey = "standalone." + key;


 506                 int len = patternKeys.length;
 507                 List<String> rawPatterns = new ArrayList<>(len);
 508                 List<String> patterns = new ArrayList<>(len);
 509                 for (int i = 0; i < len; i++) {
 510                     String key = calendarPrefix + patternKeys[i];
 511                     String pattern = (String) myMap.remove(key);
 512                     if (pattern == null) {
 513                         pattern = (String) parentsMap.remove(key);
 514                     }
 515                     rawPatterns.add(i, pattern);
 516                     if (pattern != null) {
 517                         patterns.add(i, translateDateFormatLetters(calendarType, pattern));
 518                     } else {
 519                         patterns.add(i, null);
 520                     }
 521                 }
 522                 // If patterns is empty or has any nulls, discard patterns.
 523                 if (patterns.isEmpty()) {
 524                     return;
 525                 }





 526                 String key = calendarPrefix + name;
 527                 if (!rawPatterns.equals(patterns)) {
 528                     myMap.put("java.time." + key, rawPatterns.toArray(new String[len]));
 529                 }
 530                 myMap.put(key, patterns.toArray(new String[len]));
 531                 break;
 532             }
 533         }
 534     }
 535 
 536     private String translateDateFormatLetters(CalendarType calendarType, String cldrFormat) {
 537         String pattern = cldrFormat;
 538         int length = pattern.length();
 539         boolean inQuote = false;
 540         StringBuilder jrePattern = new StringBuilder(length);
 541         int count = 0;
 542         char lastLetter = 0;
 543 
 544         for (int i = 0; i < length; i++) {
 545             char c = pattern.charAt(i);


 625         fillInAbbrs(TZ_STD_LONG_KEY, TZ_STD_SHORT_KEY, map);
 626         fillInAbbrs(TZ_DST_LONG_KEY, TZ_DST_SHORT_KEY, map);
 627         fillInAbbrs(TZ_GEN_LONG_KEY, TZ_GEN_SHORT_KEY, map);
 628 
 629         // If the standard std is "Standard Time" and daylight std is "Summer Time",
 630         // replace the standard std with the generic std to avoid using
 631         // the same abbrivation except for Australia time zone names.
 632         String std = map.get(TZ_STD_SHORT_KEY);
 633         String dst = map.get(TZ_DST_SHORT_KEY);
 634         String gen = map.get(TZ_GEN_SHORT_KEY);
 635         if (std != null) {
 636             if (dst == null) {
 637                 // if dst is null, create long and short names from the standard
 638                 // std. ("Something Standard Time" to "Something Daylight Time",
 639                 // or "Something Time" to "Something Summer Time")
 640                 String name = map.get(TZ_STD_LONG_KEY);
 641                 if (name != null) {
 642                     if (name.contains("Standard Time")) {
 643                         name = name.replace("Standard Time", "Daylight Time");
 644                     } else if (name.endsWith("Mean Time")) {
 645                         if (!name.startsWith("Greenwich ")) {
 646                             name = name.replace("Mean Time", "Summer Time");
 647                         }
 648                     } else if (name.endsWith(" Time")) {
 649                         name = name.replace(" Time", " Summer Time");
 650                     }
 651                     map.put(TZ_DST_LONG_KEY, name);
 652                     fillInAbbrs(TZ_DST_LONG_KEY, TZ_DST_SHORT_KEY, map);
 653                 }
 654             }
 655             if (gen  == null) {
 656                 String name = map.get(TZ_STD_LONG_KEY);
 657                 if (name != null) {
 658                     if (name.endsWith("Standard Time")) {
 659                         name = name.replace("Standard Time", "Time");
 660                     } else if (name.endsWith("Mean Time")) {
 661                         if (!name.startsWith("Greenwich ")) {
 662                             name = name.replace("Mean Time", "Time");
 663                         }
 664                     }
 665                     map.put(TZ_GEN_LONG_KEY, name);
 666                     fillInAbbrs(TZ_GEN_LONG_KEY, TZ_GEN_SHORT_KEY, map);
 667                 }
 668             }
 669         }
 670     }
 671 
 672     private void fillInAbbrs(String longKey, String shortKey, Map<String, String> map) {
 673         String abbr = map.get(shortKey);
 674         if (abbr == null) {
 675             String name = map.get(longKey);
 676             if (name != null) {
 677                 abbr = toAbbr(name);
 678                 if (abbr != null) {
 679                     map.put(shortKey, abbr);
 680                 }
 681             }
 682         }
 683     }
 684 


 711             break;
 712 
 713         // TODO: support 'c' and 'e' in JRE SimpleDateFormat
 714         // Use 'u' and 'E' for now.
 715         case 'c':
 716         case 'e':
 717             switch (count) {
 718             case 1:
 719                 sb.append('u');
 720                 break;
 721             case 3:
 722             case 4:
 723                 appendN('E', count, sb);
 724                 break;
 725             case 5:
 726                 appendN('E', 3, sb);
 727                 break;
 728             }
 729             break;
 730 
 731         case 'l':
 732             // 'l' is deprecated as a pattern character. Should be ignored.
 733             break;
 734 
 735         case 'u':
 736             // Use 'y' for now.
 737             appendN('y', count, sb);
 738             break;
 739 
 740         case 'v':
 741         case 'V':
 742             appendN('z', count, sb);
 743             break;
 744 
 745         case 'Z':
 746             if (count == 4 || count == 5) {
 747                 sb.append("XXX");
 748             }
 749             break;
 750 

 751         case 'U':
 752         case 'q':
 753         case 'Q':

 754         case 'g':
 755         case 'j':
 756         case 'A':
 757             throw new InternalError(String.format("Unsupported letter: '%c', count=%d, id=%s%n",
 758                                                   cldrLetter, count, id));
 759         default:
 760             appendN(cldrLetter, count, sb);
 761             break;
 762         }
 763     }
 764 
 765     private void appendN(char c, int n, StringBuilder sb) {
 766         for (int i = 0; i < n; i++) {
 767             sb.append(c);
 768         }
 769     }
 770 
 771     private static boolean hasNulls(Object[] array) {
 772         for (int i = 0; i < array.length; i++) {
 773             if (array[i] == null) {
 774                 return true;
 775             }
 776         }
 777         return false;
 778     }