Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.adobe.xfa.ut.LcData Maven / Gradle / Ivy
/*
* ADOBE CONFIDENTIAL
*
* Copyright 2005 Adobe Systems Incorporated All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains the property of
* Adobe Systems Incorporated and its suppliers, if any. The intellectual and
* technical concepts contained herein are proprietary to Adobe Systems
* Incorporated and its suppliers and may be covered by U.S. and Foreign
* Patents, patents in process, and are protected by trade secret or copyright
* law. Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained from
* Adobe Systems Incorporated.
*/
package com.adobe.xfa.ut;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import com.adobe.xfa.ut.lcdata.LcBundle;
/**
* LcData defines locale data objects in support of localization.
* The source of the localized data was originally Java's JDK 1.4. However
* this has long since been converted to use Unicode's CLDR 1.3 data. CLDR
* data has been slightly modified to conform to XFA standards.
*
* The C++ implementation stores locale data in a static store. Alas,
* the Java compiler's 64K data limit precludes us from doing the same.
* Instead, the Java implementation stores locale data in properties files
* -- one for each supported locale.
*
* Here's a snippet of code illustrating the use of {@link LcData} to retrieve
* abbreviated month names, and retrieve a date format.
*
*
*
*
* import com.adobe.xfa.ut.LcData;
* ...
* LcData data = new lcData("es_ES");
* String s = data.getAbbrMonthName(LcData.FEB);
* System.out.println(s);
* data = new lcData("pt_BR");
* s = data.getDateFormat(LcData.SHORT);
* System.out.println(s);
*
*
*
*
* Besides the static store, this class also maintains a more dynamic
* thread-local store. The application can provide its own locale data
* definitions to be stored in the runtime store. In general, when locale
* information is requested, the runtime store is searched first, then the
* static store. This happens on every single request, so if the runtime
* store changes between two calls on an LcData data instance, the two calls
* may return different results. In practice, LcData object have such limited
* lifespans that this doesn't become an issue.
*
*
* To populate the runtime store, the application calls method LcData.update()
* with an instance of the nested class LcDada.LcRunTimeData. This class contains
* several arrays of strings that hold locale information. A number of
* public static final int constants provided may be used as indexes into these
* arrays.
*
*
* @author Mike P. Tardif
* @exclude from published api.
*/
@SuppressWarnings("unchecked")
public class LcData {
/**
* Nested class describing a locale's data.
* @exclude from published api.
*/
public static class LcRunTimeData {
public final String localeName;
public final String[] monthNames = new String[12]; // month names (JAN, ..., DEC).
public final String[] abbrMonthNames = new String[12]; // abbr month names (JAN, ..., DEC).
public final String[] dayNames = new String[7]; // weekday names (SUN, ..., SAT).
public final String[] abbrWeekdayNames = new String[7]; // abbr weekday names (SUN, ..., SAT).
public final String[] meridiemNames = new String[2]; // meridiem names (AM, PM).
public final String[] eraNames = new String[2]; // era names (BC, AD).
public final String[] datePatterns = new String[4]; // date format patterns (FULL, ..., SHORT).
public final String[] timePatterns = new String[4]; // time format patterns (FULL, ..., SHORT).
public final String[] dateTimeSymbols = new String[1]; // date and time symbols.
public final String[] numberPatterns = new String[3]; // number format patterns (NUMERIC, ..., PERCENT).
public final String[] numericSymbols = new String[5]; // numeric symbols (NUM_DECIMAL, ..., NUM_ZERO).
public final String[] currencySymbols = new String[3]; // currency symbols (CUR_SYMBOL, ..., CUR_DECIMAL).
public final List typefaceList = new ArrayList(); // typeface names.
public LcRunTimeData(String sLocaleName) {
int index = localeIndex(sLocaleName);
if (index >= 0)
sLocaleName = gLocaleList[index];
else
sLocaleName = LcLocale.normalize(sLocaleName);
localeName = sLocaleName;
}
}
/* Weekday Names */
public static final int SUN = 0;
public static final int MON = 1;
public static final int TUE = 2;
public static final int WED = 3;
public static final int THU = 4;
public static final int FRI = 5;
public static final int SAT = 6;
/* Month Names */
public static final int JAN = 0;
public static final int FEB = 1;
public static final int MAR = 2;
public static final int APR = 3;
public static final int MAY = 4;
public static final int JUN = 5;
public static final int JUL = 6;
public static final int AUG = 7;
public static final int SEP = 8;
public static final int OCT = 9;
public static final int NOV = 10;
public static final int DEC = 11;
/* Meridiem Names */
public static final int AM = 0;
public static final int PM = 1;
/* Era Names */
public static final int BC = 0;
public static final int AD = 1;
/* Date & Time Patterns */
public static final int DEFLT = 2;
public static final int FULL = 0;
public static final int LONG = 1;
public static final int MED = 2;
public static final int SHORT = 3;
/* Number Patterns */
public static final int NUMERIC = 0;
public static final int CURRENCY = 1;
public static final int PERCENT = 2;
/* Numeric Symbols */
public static final int NUM_DECIMAL = 0;
public static final int NUM_GROUPING = 1;
public static final int NUM_PERCENT = 2;
public static final int NUM_MINUS = 3;
public static final int NUM_ZERO = 4;
/* Currency Symbols */
public static final int CUR_SYMBOL = 0;
public static final int CUR_ISONAME = 1;
public static final int CUR_DECIMAL = 2;
/* Date, Time and DateTime Format Styles */
public static final int DEFLT_FMT = 0;
public static final int SHORT_FMT = 1;
public static final int MED_FMT = 2;
public static final int LONG_FMT = 3;
public static final int FULL_FMT = 4;
/* Numeric Format Styles */
public static final int INTEGRAL_FMT = 0;
public static final int DECIMAL_FMT = 1;
public static final int CURRENCY_FMT = 2;
public static final int PERCENT_FMT = 3;
/* Numeric Format Options */
public static final int WITHOUT_RADIX = 0x0;
public static final int WITHOUT_GROUPINGS = 0x0;
public static final int WITH_GROUPINGS = 0x1;
public static final int WITH_ZEDS = 0x0;
public static final int WITH_EIGHTS = 0x2;
public static final int WITH_RADIX = 0x4;
public static final int KEEP_NINES = 0x8;
public static final int withWidth(int width) {
return width << 16;
}
public static final int withPrecision(int prec) {
return (prec & 0xff) << 8;
}
public static final int WITHOUT_CATEGORIES = 0x0;
public static final int WITH_CATEGORIES = 0x1;
/* Max no. of significant digits in a double */
private static final int MAX_DBL_DIG = 18;
/* Max no. of significant digits in an integer */
private static final int MAX_INT_DIG = 10;
/* Max width before precision loss in a double */
private static final int MAX_DBL_WIDTH = 15;
/* Date Pattern Mask */
private static final String gpDateMask = "GYMD EJFwW ";
/* Time Pattern Mask */
private static final String gpTimeMask = " KHMSF AhkZz";
/* Thread local storage for the runtime store */
private final static ThreadLocal> mRuntimeMap = new ThreadLocal>() {
protected Map initialValue() {
return new HashMap();
}
};
/**
* The locales for which we have data in resources.
* Must keep in value-sorted order (non case sensitive)!
*/
private final static String[] gLocaleList = {
LcLocale.Arabic,
LcLocale.Arabic_UAE,
LcLocale.Arabic_Bahrain,
LcLocale.Arabic_Algeria,
LcLocale.Arabic_Egypt,
LcLocale.Arabic_Iraq,
LcLocale.Arabic_Jordan,
LcLocale.Arabic_Kuwait,
LcLocale.Arabic_Lebanon,
LcLocale.Arabic_Libya,
LcLocale.Arabic_Morocco,
LcLocale.Arabic_Oman,
LcLocale.Arabic_Qatar,
LcLocale.Arabic_SaudiArabia,
LcLocale.Arabic_Sudan,
LcLocale.Arabic_Syria,
LcLocale.Arabic_Tunisia,
LcLocale.Arabic_Yemen,
LcLocale.Azerbaijani,
LcLocale.Azerbaijani_Azerbaijan,
LcLocale.Azerbaijani_Cyrillic,
LcLocale.Azerbaijani_Cyrillic_Azerbaijan,
LcLocale.Azerbaijani_Latin,
LcLocale.Azerbaijani_Latin_Azerbaijan,
LcLocale.Byelorussian,
LcLocale.Byelorussian_Belarus,
LcLocale.Bulgarian,
LcLocale.Bulgarian_Bulgaria,
LcLocale.Bosnian,
LcLocale.Bosnian_BosniaHerzegovina,
LcLocale.C,
LcLocale.Catalan,
LcLocale.Catalan_Spain,
LcLocale.Czech,
LcLocale.Czech_CzechRepublic,
LcLocale.Danish,
LcLocale.Danish_Denmark,
LcLocale.German,
LcLocale.German_Austria,
LcLocale.German_Belgium,
LcLocale.German_Switzerland,
LcLocale.German_Germany,
LcLocale.German_Liechtenstein,
LcLocale.German_Luxembourg,
LcLocale.Greek,
LcLocale.Greek_Greece,
LcLocale.English,
LcLocale.English_Australia,
LcLocale.English_Belgium,
LcLocale.English_Canada,
LcLocale.English_UK,
LcLocale.English_UK_Euro,
LcLocale.English_HongKong,
LcLocale.English_Ireland,
LcLocale.English_India,
LcLocale.English_NewZealand,
LcLocale.English_Philippines,
LcLocale.English_Singapore,
LcLocale.English_US,
LcLocale.English_US_Posix,
LcLocale.English_VirginIslands,
LcLocale.English_SouthAfrica,
LcLocale.Spanish,
LcLocale.Spanish_Argentina,
LcLocale.Spanish_Bolivia,
LcLocale.Spanish_Chile,
LcLocale.Spanish_Colombia,
LcLocale.Spanish_CostaRica,
LcLocale.Spanish_DominicanRepublic,
LcLocale.Spanish_Ecuador,
LcLocale.Spanish_Spain,
LcLocale.Spanish_Guatemala,
LcLocale.Spanish_Honduras,
LcLocale.Spanish_Mexico,
LcLocale.Spanish_Nicaragua,
LcLocale.Spanish_Panama,
LcLocale.Spanish_Peru,
LcLocale.Spanish_PuertoRico,
LcLocale.Spanish_Paraguay,
LcLocale.Spanish_ElSalvador,
LcLocale.Spanish_US,
LcLocale.Spanish_Uruguay,
LcLocale.Spanish_Venezuela,
LcLocale.Estonian,
LcLocale.Estonian_Estonia,
LcLocale.Basque,
LcLocale.Basque_Spain,
LcLocale.Persian,
LcLocale.Persian_Iran,
LcLocale.Finnish,
LcLocale.Finnish_Finland,
LcLocale.French,
LcLocale.French_Belgium,
LcLocale.French_Canada,
LcLocale.French_Switzerland,
LcLocale.French_France,
LcLocale.French_Luxembourg,
LcLocale.Hebrew,
LcLocale.Hebrew_Israel,
LcLocale.Hindi,
LcLocale.Hindi_India,
LcLocale.Croatian,
LcLocale.Croatian_Croatia,
LcLocale.Hungarian,
LcLocale.Hungarian_Hungary,
LcLocale.Armenian,
LcLocale.Armenian_Armenia,
LcLocale.Indonesian,
LcLocale.Indonesian_Indonesia,
LcLocale.Icelandic,
LcLocale.Icelandic_Iceland,
LcLocale.Italian,
LcLocale.Italian_Switzerland,
LcLocale.Italian_Italy,
LcLocale.Japanese,
LcLocale.Japanese_Japan,
LcLocale.Kazakh,
LcLocale.Kazakh_Kazakhstan,
LcLocale.Khmer,
LcLocale.Khmer_Cambodia,
LcLocale.Korean,
LcLocale.Korean_Korea,
LcLocale.Korean_Korea_Hani,
LcLocale.Lao,
LcLocale.Lao_Laos,
LcLocale.Lithuanian,
LcLocale.Lithuanian_Lithuania,
LcLocale.Latvian,
LcLocale.Latvian_Latvia,
LcLocale.Macedonian,
LcLocale.Macedonian_Macedonia,
LcLocale.Malay,
LcLocale.Malay_Malaysia,
LcLocale.Norwegian_Bokmal,
LcLocale.Norwegian_Bokmal_Norway,
LcLocale.Dutch,
LcLocale.Dutch_Belgium,
LcLocale.Dutch_Netherlands,
LcLocale.Norwegian_Nynorsk,
LcLocale.Norwegian_Nynorsk_Norway,
"no",
"no_NO",
"no_NO_NY",
LcLocale.Polish,
LcLocale.Polish_Poland,
LcLocale.Portuguese,
LcLocale.Portuguese_Brazil,
LcLocale.Portuguese_Portugal,
LcLocale.Romanian,
LcLocale.Romanian_Romania,
"root",
LcLocale.Russian,
LcLocale.Russian_Russia,
LcLocale.Russian_Ukraine,
LcLocale.Serbo_Croatian,
LcLocale.Serbo_Croatian_BosniaHerzegovina,
LcLocale.Serbo_Croatian_SerbiaMontenegro,
LcLocale.Serbo_Croatian_Croatia,
LcLocale.Slovak,
LcLocale.Slovak_Slovakia,
LcLocale.Slovenian,
LcLocale.Slovenian_Slovenia,
LcLocale.Albanian,
LcLocale.Albanian_Albania,
LcLocale.Serbian,
LcLocale.Serbian_Yugoslavia,
LcLocale.Serbian_Cyrillic,
LcLocale.Serbian_Cyrillic_SerbiaMontenegro,
LcLocale.Serbian_Latin,
LcLocale.Serbian_Latin_SerbiaMontenegro,
LcLocale.Swedish,
LcLocale.Swedish_Finland,
LcLocale.Swedish_Sweden,
LcLocale.Thai,
LcLocale.Thai_Thailand,
LcLocale.Thai_Thailand_Traditional,
LcLocale.Tagalog,
LcLocale.Tagalog_Philippines,
LcLocale.Turkish,
LcLocale.Turkish_Turkey,
LcLocale.Ukrainian,
LcLocale.Ukrainian_Ukraine,
LcLocale.Vietnamese,
LcLocale.Vietnamese_Vietnam,
LcLocale.Chinese,
LcLocale.Chinese_China,
"zh_Hans",
"zh_Hans_CN",
"zh_Hans_SG",
"zh_Hant",
"zh_Hant_HK",
"zh_Hant_TW",
LcLocale.Chinese_HongKong,
LcLocale.Chinese_Singapore,
LcLocale.Chinese_Taiwan
};
/**
* Holds the static locale data loaded from properties files.
* Entries are loaded as they are needed.
*/
private static final Map[] staticData = new Map[gLocaleList.length];
/**
* Contains the index of the parent locale.
* The root locale has a parent index of -1.
*/
private static final int[] staticParentIndex = new int[gLocaleList.length];
// The arrays allow mapping aliases that omit the script (e.g., "az_AZ")
// to the fully specified locale name (e.g., "az_Latn_AZ").
private static final int numAliases = 6;
private static final int[] aliasFromIndex = new int[numAliases];
private static final int[] aliasToIndex = new int[numAliases];
/**
* The index of the locale that is the "root" locale.
*/
private static final int rootIndex;
static {
if (Assertions.isEnabled)
for (int i = 0; i < gLocaleList.length - 1; i++)
assert String.CASE_INSENSITIVE_ORDER.compare(gLocaleList[i], gLocaleList[i + 1]) < 0;
rootIndex = localeIndex("root");
assert rootIndex != -1;
// First pass at calculating parent
staticParentIndex[rootIndex] = -1;
for (int i = 0; i < gLocaleList.length; i++) {
if (i == rootIndex)
continue;
String sLocaleName = gLocaleList[i];
if (sLocaleName.indexOf('_') == -1)
staticParentIndex[i] = rootIndex;
for (int j = i + 1; j < gLocaleList.length; j++) {
String sFollowingLocaleName = gLocaleList[j];
if (sFollowingLocaleName.length() > sLocaleName.length() &&
sFollowingLocaleName.startsWith(sLocaleName) &&
sFollowingLocaleName.charAt(sLocaleName.length()) == '_')
staticParentIndex[j] = i;
else
break;
}
}
// For az and sr, there are both Latn and Cyrl scripts:
// The parents of az_Cyrl and sr_Latn are root.
// The parents of az_Latn and sr_Cyrl are az and sr.
initParentIndex("az_Cyrl", rootIndex);
initParentIndex("sr_Latn", rootIndex);
// Where a country code may have a script, if the locale is
// provided without the script code, we treat that as an alias
// for the locale with the script code.
int index = 0;
initScriptAlias(index++, "zh_CN", "zh_Hans_CN");
initScriptAlias(index++, "zh_SG", "zh_Hans_SG");
initScriptAlias(index++, "zh_HK", "zh_Hant_HK");
initScriptAlias(index++, "zh_TW", "zh_Hant_TW");
initScriptAlias(index++, "az_AZ", "az_Latn_AZ");
initScriptAlias(index++, "sr_CS", "sr_Cyrl_CS");
assert index == numAliases;
// for (int i = 0; i < gLocaleList.length; i++)
// System.out.println(gLocaleList[i] + " - " + (staticParentIndex[i] == -1 ? "" : gLocaleList[staticParentIndex[i]]));
}
private static int localeIndex(String sLocaleName) {
return Arrays.binarySearch(gLocaleList, sLocaleName, String.CASE_INSENSITIVE_ORDER);
}
private static void initParentIndex(String sLocaleName, int parentIndex) {
int index = localeIndex(sLocaleName);
staticParentIndex[index] = parentIndex;
}
private static void initScriptAlias(int index, String sLocaleName, String sRealLocaleName) {
aliasFromIndex[index] = localeIndex(sLocaleName);
aliasToIndex[index] = localeIndex(sRealLocaleName);
}
private static int mapLocaleIndexToAlias(int localeIndex) {
for (int i = 0; i < numAliases; i++) {
if (aliasFromIndex[i] == localeIndex)
return aliasToIndex[i];
}
return localeIndex;
}
private final String msLocale; // normalized UTS #35 locale name.
private final int mnIndex; // index into static data
/**
* Instantiates an LcData object for the given locale.
*
* @param locale the locale name.
*/
public LcData(String locale) {
int localeIndex = localeIndex(locale);
if (localeIndex >= 0) {
locale = gLocaleList[localeIndex]; // save normalized name
localeIndex = mapLocaleIndexToAlias(localeIndex);
}
else {
locale = LcLocale.normalize(locale);
String sLocaleName = locale;
while (true) {
localeIndex = localeIndex(sLocaleName);
if (localeIndex >= 0) { // matched a static data entry?
localeIndex = mapLocaleIndexToAlias(localeIndex);
break;
}
if (localeIndex == -1) {
// This is before any other entry in the list
localeIndex = rootIndex;
break;
}
int delim = sLocaleName.lastIndexOf('_');
if (delim == -1) {
localeIndex = rootIndex;
break;
}
sLocaleName = sLocaleName.substring(0, delim);
}
}
assert localeIndex >= 0;
msLocale = locale;
mnIndex = localeIndex;
}
private static Map getStaticData(int staticDataIndex) {
Map result = staticData[staticDataIndex];
if (result == null) {
result = loadStaticData(gLocaleList[staticDataIndex]);
assert result != null;
staticData[staticDataIndex] = result;
}
return result;
}
private static Map loadStaticData(String sLocale) {
if (sLocale.equals("root"))
sLocale = "";
final String resourceName = LcBundle.BUNDLE_BASE + (sLocale.length() == 0 ? "" : '_') + sLocale + ".properties";
InputStream stream = LcData.class.getClassLoader().getResourceAsStream(resourceName);
Properties properties = new Properties();
try {
properties.load(stream);
}
catch (IOException ignored) {
assert false;
return null;
}finally{
try{
stream.close();
}catch(IOException streamCantBeClosedException){}
stream = null;
}
Map staticData = new HashMap(properties.size());
Enumeration keys = properties.keys();
while (keys.hasMoreElements()) {
String key = (String)keys.nextElement();
staticData.put(key, (String)properties.get(key));
}
return staticData;
}
/**
* Gets this LcData object's locale.
*
* @return Locale name (e.g., "ar_SA").
*/
public String getLocale() {
return msLocale;
}
/**
* Validates the given runtime locale data.
*
* Applications should validate() the data before calling update().
*
* @param oLcData the some runtime locale data.
* @return Boolean true if valid and false otherwise.
*/
public static boolean validate(LcRunTimeData oLcData) {
String decimal = oLcData.numericSymbols[NUM_DECIMAL];
if (decimal != null && decimal.equals(oLcData.numericSymbols[CUR_DECIMAL])) {
return false;
}
return true;
}
/**
* Reset this class's runtime store of locale data to its
* internal defaults.
*/
public static void reset() {
getMap().clear();
}
/**
* Updates (replaces) this class's runtime store of data
* for the given locale with the given locale data.
*
* @param oLcData the runtime locale data.
*/
public static void update(LcRunTimeData oLcData) {
Map map = getMap();
map.put(oLcData.localeName, oLcData);
}
/**
* Gets the locale data for the given locale
* from this class's runtime store.
*
* @param sLocale the locale name to search for.
* @return The runtime locale data if found and null otherwise.
*/
public static LcRunTimeData get(String sLocale) {
LcRunTimeData oRunTimeData = getMap().get(sLocale);
if (oRunTimeData == null)
oRunTimeData = new LcRunTimeData(sLocale);
return oRunTimeData;
}
private static final PropertyRetriever retrieveWeekdayNameProperty = new PropertyRetriever() {
public String retrieveRuntime(LcRunTimeData runtimeData, int key) {
return runtimeData.dayNames[key];
}
public String retrieveStatic(Map staticData, int key) {
return staticData.get(LcBundle.getLongDayProperty(key));
}
};
/**
* Gets the name of the given day of the week.
*
* @param weekday the day of the week in the range of values 0-6,
* where (0 = Sunday).
* @return The weekday name, or the empty string upon error.
*/
public String getWeekDayName(int weekday) {
if (weekday < SUN || weekday > SAT) {
assert false;
return "";
}
return searchRuntimeThenStaticStore(weekday, retrieveWeekdayNameProperty);
}
private static final PropertyRetriever retrieveAbbrWeekdayNameProperty = new PropertyRetriever() {
public String retrieveRuntime(LcRunTimeData runtimeData, int key) {
return runtimeData.abbrWeekdayNames[key];
}
public String retrieveStatic(Map staticData, int key) {
return staticData.get(LcBundle.getShortDayProperty(key));
}
};
/**
* Gets the abbreviated name of the given day of the week.
*
* @param weekday the day of the week in the range of values 0-6,
* where (0 = Sunday).
* @return The abbreviated weekday name, or the empty string upon error.
*/
public String getAbbrWeekdayName(int weekday) {
if (weekday < SUN || weekday > SAT) {
assert false;
return "";
}
return searchRuntimeThenStaticStore(weekday, retrieveAbbrWeekdayNameProperty);
}
private static final PropertyRetriever retrieveMonthNameProperty = new PropertyRetriever() {
public String retrieveRuntime(LcRunTimeData runtimeData, int key) {
return runtimeData.monthNames[key];
}
public String retrieveStatic(Map staticData, int key) {
return staticData.get(LcBundle.getLongMonthProperty(key));
}
};
/**
* Gets the name of the given month of the year.
*
* @param month the month of the year in the range of values 0-11,
* where (0 = January).
* @return The month name, or the empty string upon error.
*/
public String getMonthName(int month) {
if (month < JAN || month > DEC) {
assert false;
return "";
}
return searchRuntimeThenStaticStore(month, retrieveMonthNameProperty);
}
private static final PropertyRetriever retrieveMonthAbbrNamesProperty = new PropertyRetriever() {
public String retrieveRuntime(LcRunTimeData runtimeData, int key) {
return runtimeData.abbrMonthNames[key];
}
public String retrieveStatic(Map staticData, int key) {
return staticData.get(LcBundle.getShortMonthProperty(key));
}
};
/**
* Gets the abbreviated name of the given month of the year.
*
* @param month the month of the year in the range of values 0-11,
* where (0 = January).
* @return The abbreviated month name, or the empty string upon error.
*/
public String getAbbrMonthName(int month) {
if (month < JAN || month > DEC) {
assert false;
return "";
}
return searchRuntimeThenStaticStore(month, retrieveMonthAbbrNamesProperty);
}
private static final PropertyRetriever retrieveMeridiemNameProperty = new PropertyRetriever() {
public String retrieveRuntime(LcRunTimeData runtimeData, int key) {
return runtimeData.meridiemNames[key];
}
public String retrieveStatic(Map staticData, int key) {
return staticData.get(LcBundle.getMeridiemProperty(key));
}
};
/**
* Gets the name of the given aspect of the meridiem.
*
* @param aspect an aspect of the meridiem in the range of values 0-1,
* where (0 = AM, 1 = PM).
* @return The meridiem name, or the empty string upon error.
*/
public String getMeridiemName(int aspect) {
if (aspect < AM || aspect > PM) {
assert false;
return "";
}
return searchRuntimeThenStaticStore(aspect, retrieveMeridiemNameProperty);
}
private static final PropertyRetriever retrieveEraNameProperty = new PropertyRetriever() {
public String retrieveRuntime(LcRunTimeData runtimeData, int key) {
return runtimeData.eraNames[key];
}
public String retrieveStatic(Map staticData, int key) {
return staticData.get(LcBundle.getEraProperty(key));
}
};
/**
* Gets the name of the given era.
*
* @param era an era of the calendar in the range of values 0-1,
* where (0 = BC, 1 = AD).
* @return The era name, or the empty string upon error.
*/
public String getEraName(int era) {
if (era < BC || era > AD) {
assert false;
return "";
}
return searchRuntimeThenStaticStore(era, retrieveEraNameProperty);
}
private static final PropertyRetriever retrieveDatePatternProperty = new PropertyRetriever() {
public String retrieveRuntime(LcRunTimeData runtimeData, int key) {
return runtimeData.datePatterns[key];
}
public String retrieveStatic(Map staticData, int key) {
return staticData.get(LcBundle.getDateFormatProperty(key));
}
};
/**
* Gets the date format in the given style.
*
* @param style the style of the format in the range of values 0-4,
* where (0 = default, 1 = short, 2 = medium, 3 = long, 4 = full).
* @return The date format.
*/
public String getDateFormat(int style) {
if (style < 0 || style > 4)
style = 2;
if (style == 0)
style = 2;
return searchRuntimeThenStaticStore(4 - style, retrieveDatePatternProperty);
}
private static final PropertyRetriever retrieveTimePatternProperty = new PropertyRetriever() {
public String retrieveRuntime(LcRunTimeData runtimeData, int key) {
return runtimeData.timePatterns[key];
}
public String retrieveStatic(Map staticData, int key) {
return staticData.get(LcBundle.getTimeFormatProperty(key));
}
};
/**
* Gets the time format in the given style.
*
* @param style the style of the format in the range of values 0-4,
* where (0 = default, 1 = short, 2 = medium, 3 = long, 4 = full).
* @return The time format.
*/
public String getTimeFormat(int style) {
if (style < 0 || style > 4)
style = 2;
if (style == 0)
style = 2;
return searchRuntimeThenStaticStore(4 - style, retrieveTimePatternProperty);
}
private static final PropertyRetriever retrieveDateTimeSymbolsProperty = new PropertyRetriever() {
public String retrieveRuntime(LcRunTimeData runtimeData, int key) {
return runtimeData.dateTimeSymbols[0];
}
public String retrieveStatic(Map staticData, int key) {
return staticData.get(LcBundle.getDateTimeSymbolsProperty());
}
};
private static final PropertyRetriever retrieveDateTimeFormatProperty = new PropertyRetriever() {
public String retrieveRuntime(LcRunTimeData runtimeData, int key) {
return null;
}
public String retrieveStatic(Map staticData, int key) {
return staticData.get(LcBundle.getDateTimeFormatProperty());
}
};
/**
* Gets the date time pattern.
*
* @return The date time pattern.
*/
public String getDateTimePattern() {
return searchRuntimeThenStaticStore(0, retrieveDateTimeSymbolsProperty);
}
/**
* Gets the datetime format in the given style.
*
* @param style the style of the format in the range of values 0-4,
* where (0 = default, 1 = short, 2 = medium, 3 = long, 4 = full).
* @param type the type of the format in the range of values 0-1,
* where (0 = w/o picture categories, 1 = w picture categories).
* @return The date time format.
*/
public String getDateTimeFormat(int style, int type) {
if (style < 0 || 4 < style)
style = 2;
//
// Search the static store (resource bundles). The equivalent
// dateTime pattern is not present in the runtime store, so do
// not search there.
//
StringBuilder sDateTimeFmt = new StringBuilder(searchStaticStore(0, retrieveDateTimeFormatProperty));
if (type == 0) {
String sDateFmt = getDateFormat(style);
String sTimeFmt = getTimeFormat(style);
int nPat = sDateTimeFmt.indexOf("date{}");
if (nPat >= 0)
sDateTimeFmt.replace(nPat, nPat + 6, sDateFmt);
nPat = sDateTimeFmt.indexOf("time{}");
if (nPat >= 0)
sDateTimeFmt.replace(nPat, nPat + 6, sTimeFmt);
}
else if (type == 1) {
String sDateFmt = getDateFormat(style);
String sTimeFmt = getTimeFormat(style);
int nPat = sDateTimeFmt.indexOf("date{}");
if (nPat >= 0)
sDateTimeFmt.insert(nPat + 5, sDateFmt);
nPat = sDateTimeFmt.indexOf("time{}");
if (nPat >= 0)
sDateTimeFmt.insert(nPat + 5, sTimeFmt);
}
return sDateTimeFmt.toString();
}
/**
* Gets the local date format in the given style.
*
* @param style the style of the format in the range of values 0-4,
* where (0 = default, 1 = short, 2 = medium, 3 = long, 4 = full).
* @return The date format.
*/
public String getLocalDateFormat(int style) {
String date = getDateFormat(style);
if (StringUtils.isEmpty(date))
return "";
String pattern = getDateTimePattern();
return xlate(date, pattern, gpDateMask);
}
/**
* Gets the local time format in the given style.
*
* @param style the style of the format in the range of values 0-4,
* where (0 = default, 1 = short, 2 = medium, 3 = long, 4 = full).
* @return The time format.
*/
public String getLocalTimeFormat(int style) {
String time = getTimeFormat(style);
if (StringUtils.isEmpty(time))
return "";
String pattern = getDateTimePattern();
return xlate(time, pattern, gpTimeMask);
}
/**
* Gets the local datetime format.
*
* This method is not functional yet.
*
* @return The date time format.
*/
public String getLocalDateTimeFormat() {
return "";
}
private static final PropertyRetriever retrieveNumberPatternProperty = new PropertyRetriever() {
public String retrieveRuntime(LcRunTimeData runtimeData, int key) {
return runtimeData.numberPatterns[key];
}
public String retrieveStatic(Map staticData, int key) {
return staticData.get(LcBundle.getNumberFormatProperty(key));
}
};
/**
* Gets the numeric format in the given style.
*
* @param style the style of the format in the range of values 0-2,
* where (0 = number, 1 = currency, 2 = percentage).
* @return The numeric format.
*/
public String getNumericFormat(int style) {
if (style < NUMERIC || style > PERCENT) {
assert false;
return "";
}
return searchRuntimeThenStaticStore(style, retrieveNumberPatternProperty);
}
/**
* Gets the number format in the given style.
*
* @param style in the range of values 0-2,
* where (0 = integral, 1 = decimal, 2 = currency).
* @param option in the set of format options:
*
* bit 1: reset => w/o commas; set => w/ commas.
* bit 2: reset => w/ fractional z's; set => w/ fractional 8's.
* bit 4: reset => w/o radix; set => w/ radix.
* bit 8-15: the precision.
* bit 16: reset => keep precision; set => trim precision.
* bit 17-24: the width.
*
*/
public String getNumberFormat(int style, int option) {
if (style < INTEGRAL_FMT || style > PERCENT_FMT) {
//
// Retrieve the locale's numeric format. Localized formats
// are all in ASCII and embed no literals, so we take advantage
// of this in the code that follows. Admittedly, this code ough
// to live in he LcNum class.
//
style = DECIMAL_FMT;
}
StringBuilder sFormat = new StringBuilder(
getNumericFormat((style > 0) ? style - 1 : style));
//
// Use any alternate part because they handle negative values.
//
int nBar = sFormat.indexOf("|");
if (nBar >= 0) {
sFormat.delete(0, nBar + 1);
}
//
// Determine position of radix (or anything like it)
// and the replicating part of the pattern, i.e., from
// the separator to this radix.
//
final String[] dotChars = { ".", "v", "V", "E", " ", "%" };
int nDot = -1;
for (int i = 0; i < dotChars.length; i++) {
nDot = sFormat.indexOf(dotChars[i]);
if (nDot >= 0)
break;
}
if (nDot < 0) {
nDot = sFormat.length();
}
else if (StringUtils.skipOver(sFormat, "89zZ", nDot - 1) != 1) {
nDot = sFormat.length();
}
StringBuilder sZZZ = new StringBuilder();
int nZed = sFormat.indexOf("z,");
if (nZed >= 0) {
//
// Watson 1230768. Handle locales, like India, that have
// pictures with more than one grouping symbol.
//
int nSep = nDot;
int nComma = sFormat.indexOf(",", nZed + 2);
if (nComma >= 0) {
nSep = nComma;
}
if (nSep > nZed + 2) {
for (int i = 1, n = nSep - nZed - 1; i <= n; i++)
sZZZ.append('z');
}
else
sZZZ.append('z');
}
else {
nZed = 0;
}
//
// If non-integral styles Then determine width and precision.
//
int nPrec = 0;
int nWidth = MAX_INT_DIG;
if (style != INTEGRAL_FMT) {
nPrec = (option >> 8) & 0xff;
boolean trim = ((nPrec & 0x80) == 0);
nPrec &= 0x7f;
if (nPrec == 0x7f) {
nPrec = StringUtils.skipOver(sFormat, "89zZ", nDot + 1);
}
if ((option & 0xff0000) != 0) {
nWidth = (option >> 16) & 0Xff;
}
else {
nWidth = MAX_DBL_DIG;
}
//
// Fix for Watson 1229423. If the locale's format contains
// any sign pictures Then widen accordingly. Also widen if
// precision of locale's picture format is greater than requested.
//
if (sFormat.indexOf("s") >= 0) {
nWidth += 1;
}
if (sFormat.indexOf("(") >= 0) {
nWidth += 1;
}
if (sFormat.indexOf(")") >= 0) {
nWidth += 1;
}
int nFmtPrec = StringUtils.skipOver(sFormat, "89zZ", nDot + 1);
if (0 < nPrec && nPrec < nFmtPrec) {
nWidth += nFmtPrec - nPrec;
}
//
// Pare down the precision if the width is big enough to yield
// IEEE 754 64-bit double precision errors, which appears to be
// anything over 14 significant digits.
//
if (trim && nPrec > 0 && nWidth > nPrec) {
//
// Fix for Watson 1211481. If the given precision is less
// than what the locale's format dictates then widen the given
// width.
//
if (nPrec <= sFormat.length() - 1 - nDot) {
nWidth += sFormat.length() - 1 - nDot - nPrec;
}
for (int i = nWidth - 1; i > MAX_DBL_WIDTH; i--) {
//
// Never pare down the precision below what the locale's
// format dictates.
//
if (nPrec <= sFormat.length() - 1 - nDot)
break;
nPrec--;
}
}
}
//
// Fix for Watson 1483675 - If the locale's format contains
// a dollar sign or a space then widen accordingly.
//
if (style == CURRENCY_FMT) {
if (sFormat.indexOf("$") >= 0)
nWidth += 1;
if (sFormat.indexOf(" ") >= 0)
nWidth += 1;
}
//
// If percent style was wanted Then truncate after the
// percent character.
//
if (style == PERCENT_FMT) {
int nTrim = StringUtils.skipOver(sFormat, "89zZ", nDot + 1);
if (nDot < sFormat.length())
sFormat.replace(nDot + 1, nDot + 1 + nTrim, "");
//
// Fix for Watson 1483675 - If the locale's format
// contains a percent sign then widen accordingly.
//
if (sFormat.indexOf("%") >= 0)
nWidth += 1;
}
//
// If integral style was wanted Then truncate at the
// radix character.
//
else if (style == INTEGRAL_FMT || nPrec == 0
&& (option & 0x4) == WITHOUT_RADIX) {
int nTrim = StringUtils.skipOver(sFormat, "89zZ", nDot + 1);
if (nDot < sFormat.length())
sFormat.replace(nDot, nDot + nTrim + 1, "");
}
//
// Otherwise for decimal and currency styles Do
// replace fractional '9' pictures with '8's to
// requested precision,
//
else if ((option & 0x2) == WITH_EIGHTS) {
int nEight = nDot + 1;
while ((nEight = sFormat.indexOf("z", nEight)) >= 0) {
sFormat.setCharAt(nEight, '8');
}
while (sFormat.length() - nDot <= nPrec) {
sFormat.insert(nDot + 1, '8');
}
}
//
// Or replace fractional '9' pictures with 'z's to requested precision
// Fix for Watson 1322850 - add option to keep nines. Previously this
// function would force frac. digits to be either z's or 8's with no
// option for 9's.
//
else if ((option & 0x2) == WITH_ZEDS && !((option & 0x8) == KEEP_NINES)) {
int nNine = nDot + 1;
while ((nNine = sFormat.indexOf("9", nNine)) >= 0) {
sFormat.setCharAt(nNine, 'z');
}
while (sFormat.length() - nDot <= nPrec) {
sFormat.insert(nDot + 1, 'z');
}
}
//
// Replicate section from separator to radix to requested width.
//
if (StringUtils.isEmpty(sZZZ)) {
sZZZ.append('z');
} else if ((option & 0x1) == WITHOUT_GROUPINGS) {
//
// Watson 1230768. Handle locales, like India, that have
// pictures with more than one grouping symbol.
//
int nComma = nZed + 1;
sFormat.setCharAt(nComma, 'z');
while ((nComma = sFormat.indexOf(",", nComma)) >= 0 && nComma < nDot) {
sFormat.setCharAt(nComma, '8');
}
} else if ((option & 0x1) == WITH_GROUPINGS) {
sZZZ.setCharAt(0, ',');
nWidth += (nWidth + sZZZ.length()) / sZZZ.length();
}
while (sFormat.length() < nWidth) {
sFormat.insert(nZed + 1, sZZZ);
}
return sFormat.toString();
}
/**
* Gets the decimal precision of the given numeric string.
*
* @return The decimal precision or 0 for integral values.
*/
public int getNumberPrecision(String sVal) {
int nRadix = sVal.indexOf(getRadixSymbol());
if (nRadix >= 0)
return sVal.length() - nRadix - 1;
return 0;
}
private interface PropertyRetriever {
T retrieveRuntime(LcRunTimeData runtimeData, int key);
T retrieveStatic(Map staticData, int key);
}
private static final PropertyRetriever retrieveCurrencySymbolProperty = new PropertyRetriever() {
public String retrieveRuntime(LcRunTimeData runtimeData, int key) {
return runtimeData.currencySymbols[key];
}
public String retrieveStatic(Map staticData, int key) {
return staticData.get(LcBundle.getCurrencySymbolProperty(key));
}
};
private static final PropertyRetriever retrieveNumericSymbolProperty = new PropertyRetriever() {
public String retrieveRuntime(LcRunTimeData runtimeData, int key) {
return runtimeData.numericSymbols[key];
}
public String retrieveStatic(Map staticData, int key) {
return staticData.get(LcBundle.getNumericSymbolProperty(key));
}
};
private static final PropertyRetriever> retrieveTypefaceListProperty = new PropertyRetriever>() {
public List retrieveRuntime(LcRunTimeData runtimeData, int key) {
List typefaces = runtimeData.typefaceList;
return typefaces.size() == 0 ? null : typefaces;
}
public List retrieveStatic(Map staticData, int key) {
String sList = staticData.get(LcBundle.getTypefacesProperty());
if (StringUtils.isEmpty(sList))
return null;
List typefaceList = new ArrayList();
StringTokenizer tokenizer = new StringTokenizer(sList, ";");
while (tokenizer.hasMoreTokens())
typefaceList.add(tokenizer.nextToken());
return typefaceList;
}
};
private T searchRuntimeStore(int key, PropertyRetriever retriever) {
Map runtimeMap = mRuntimeMap.get();
if (runtimeMap.size() == 0)
return null;
String sLocaleName = msLocale;
int staticIndex = -1;
while (true) {
LcRunTimeData lcData = runtimeMap.get(sLocaleName);
if (lcData != null) {
T value = retriever.retrieveRuntime(lcData, key);
if (value != null)
return value;
}
// Move up to a more generic locale to see if we can find the data there.
// At the point that we reach a locale name that is in the static data,
// we'll start following the pre-built tree that has been built for the
// static locale. This ensures that we follow the same exceptions in the
// locale tree (aliases, script expansion), but is is also more efficient.
if (staticIndex >= 0) {
int parentIndex = staticParentIndex[staticIndex];
if (parentIndex < 0)
break;
sLocaleName = gLocaleList[parentIndex];
staticIndex = parentIndex;
}
else {
// We haven't found a name that corresponds to a static locale,
// so trim off a terminal segment and see if that matches.
int delim = sLocaleName.lastIndexOf('_');
if (delim == -1) {
if (sLocaleName.equals("root"))
break;
else {
sLocaleName = "root";
staticIndex = rootIndex;
}
}
else {
sLocaleName = sLocaleName.substring(0, delim);
// See if we have found a place in the static tree.
staticIndex = localeIndex(sLocaleName);
if (staticIndex >= 0)
staticIndex = mapLocaleIndexToAlias(staticIndex);
}
}
}
return null;
}
private T searchStaticStore(int key, PropertyRetriever retriever) {
int staticDataIndex = mnIndex;
while (true) {
Map lcData = getStaticData(staticDataIndex);
T value = retriever.retrieveStatic(lcData, key);
if (value != null)
return value;
staticDataIndex = staticParentIndex[staticDataIndex];
if (staticDataIndex == -1)
break;
}
assert false; // the locale data should always have a default at the root
return null;
}
/**
* Search up through the static store and then through the candidate store for a property.
*
* This method approximates what is repeated in most property retrieval methods
* in the C++ LcData class, but here it is factored out into a separate method using
* PropertyRetriever functors. Note that calling searchCandidateKey is largely
* wasteful since it searches through many of the same entries in the runtime store, but
* it is left here for compatibility.
* @param the property type
* @param key the property key
* @param retriever a property retriever functor
* @return a property value, or null
if not found
*/
private T searchRuntimeThenStaticStore(int key, PropertyRetriever retriever) {
T value = searchRuntimeStore(key, retriever);
if (value != null)
return value;
return searchStaticStore(key, retriever);
}
/**
* Gets the name of the currency.
*
* @return The currency name or the empty string upon error.
*/
public String getCurrencyName() {
return searchRuntimeThenStaticStore(CUR_ISONAME, retrieveCurrencySymbolProperty);
}
/**
* Gets the symbol of the currency.
*
* @return The currency symbol or the empty string upon error.
*/
public String getCurrencySymbol() {
return searchRuntimeThenStaticStore(CUR_SYMBOL, retrieveCurrencySymbolProperty);
}
/**
* Gets the radix of the currency.
*
* @return The currency radix or the empty string upon error.
*/
public String getCurrencyRadix() {
return searchRuntimeThenStaticStore(CUR_DECIMAL, retrieveCurrencySymbolProperty);
}
/**
* Gets the radix symbol.
*
* @return The radix symbol or the empty string upon error.
*/
public String getRadixSymbol() {
return searchRuntimeThenStaticStore(NUM_DECIMAL, retrieveNumericSymbolProperty);
}
/**
* Gets the grouping symbol.
*
* @return The grouping symbol or the empty string upon error.
*/
public String getGroupingSymbol() {
return searchRuntimeThenStaticStore(NUM_GROUPING, retrieveNumericSymbolProperty);
}
/**
* Gets the percent symbol.
*
* @return The percent symbol or the empty string upon error.
*/
public String getPercentSymbol() {
return searchRuntimeThenStaticStore(NUM_PERCENT, retrieveNumericSymbolProperty);
}
/**
* Gets the list of typefaces.
*
* @return The list of typefaces which is possibly empty upon error.
*/
public List getTypefaces() {
List typefaces = searchRuntimeThenStaticStore(0, retrieveTypefaceListProperty);
if (typefaces == null)
typefaces = Collections.emptyList();
return typefaces;
}
/**
* Gets the negative symbol.
*
* @return The negative symbol or the empty string upon error.
*/
public String getNegativeSymbol() {
return searchRuntimeThenStaticStore(NUM_MINUS, retrieveNumericSymbolProperty);
}
/**
* Gets the native zero digit symbol.
*
* @return The zero symbol or the empty string upon error.
*/
public String getZeroSymbol() {
return searchRuntimeThenStaticStore(NUM_ZERO, retrieveNumericSymbolProperty);
}
/**
* Gets the positive symbol.
*
* @return The positive symbol or the empty string upon error.
*/
public String getPositiveSymbol() {
return "+"; // as in C++ implementation
}
/**
* Gets all the supported locale names.
*
* @param oLocales the List object to be populated
* with the name of all the locales for which we have
* data.
*/
public static void getLocaleNames(List oLocales) {
//
// Add locales from the runtime store.
//
oLocales.addAll(getMap().keySet());
//
// Add locales from the static store.
//
for (int i = 0; i < gLocaleList.length; i++) {
oLocales.add(gLocaleList[i]);
}
}
/**
* Finds a locale who's currency, radix and grouping symbols match all of the
* given symbols.
*
* @param sCurrencySymbol
* the currency symbol to match.
* @param sRadixSymbol
* the decimal radix symbol to match.
* @param sGroupingSymbol
* the grouping separator symbol to match.
* @return The matching locale name or the empty string upon failure.
*/
public static String findMatchingLocale(String sCurrencySymbol,
String sRadixSymbol, String sGroupingSymbol) {
//
// Try the current locale for a match.
//
String dflt = LcLocale.getLocale();
if (testMatchingLocale(dflt, sCurrencySymbol, sRadixSymbol, sGroupingSymbol)) {
return dflt;
}
//
// Try all locales in the locale data table for a match.
//
for (int i = 0; i < gLocaleList.length; i++) {
String locale = gLocaleList[i];
if (testMatchingLocale(locale, sCurrencySymbol, sRadixSymbol, sGroupingSymbol)) {
return locale;
}
}
return "";
}
/**
* Tests whether a given locale matches.
*
* @param locale
* Name of locale to test.
* @param sCurrencySymbol
* Currency symbol to test for. Can be empty string if there is
* no need to test for currency symbol.
* @param sRadixSymbol
* Radix symbol to test for. Can be empty string if there is no
* need to test for radix symbol.
* @param sGroupingSymbol
* Grouping symbol to test for. Can be empty string if there is
* no need to test for grouping symbol.
* @return True if the named locale's symbols match the given non-empty
* symbols; false otherwise.
*/
private static boolean testMatchingLocale(String locale,
String sCurrencySymbol, String sRadixSymbol, String sGroupingSymbol) {
LcData oData = new LcData(locale);
if (!StringUtils.isEmpty(sCurrencySymbol)
&& (!oData.getCurrencySymbol().equals(sCurrencySymbol))) {
return false;
}
if (!StringUtils.isEmpty(sRadixSymbol)
&& (!oData.getRadixSymbol().equals(sRadixSymbol))) {
return false;
}
if (!StringUtils.isEmpty(sGroupingSymbol)
&& (!oData.getGroupingSymbol().equals(sGroupingSymbol))) {
return false;
}
return true;
}
private static String xlate(String pPat, String pLocal, String pMask) {
StringBuilder sBuf = new StringBuilder();
char prevChr = '\0';
int chrCnt = 0;
boolean inQuoted = false;
boolean inQuoteQuoted = false;
//
// For each character of the pattern Do ...
//
int nPatLen = pPat.length();
for (int i = 0; i < nPatLen; i++) {
char chr = pPat.charAt(i);
if (inQuoteQuoted) {
//
// If seen a quote within a quoted string ...
//
if (chr == '\'') {
chrCnt = 0; // cases like '...''
sBuf.append(chr);
} else {
inQuoted = false; // cases like '...'M
chrCnt = 1;
prevChr = chr;
}
inQuoteQuoted = false;
} else if (inQuoted) {
//
// Else if within a quoted string ...
//
if (chr == '\'') {
inQuoteQuoted = true; // cases like '...'
} else {
sBuf.append(chr); // cases like '...M
}
chrCnt++;
} else if (chr == '\'') {
//
// Else if start of a quoted string ...
//
if (chrCnt > 0) {
char c = LcData.subXlate(prevChr, pLocal, pMask); // cases
// like
// ...M'
while (chrCnt-- > 0) {
sBuf.append(c);
}
chrCnt = 0;
prevChr = 0;
}
inQuoted = true;
} else if ('a' <= chr && chr <= 'z' || 'A' <= chr && chr <= 'Z') {
//
// Else if its a metacharacter ...
//
if (chr != prevChr) {
if (chrCnt > 0) {
char c = subXlate(prevChr, pLocal, pMask); // cases
// like HHM
// or :M
while (chrCnt-- > 0) {
sBuf.append(c);
}
chrCnt = 0;
}
prevChr = chr;
}
chrCnt++;
} else if (chrCnt > 0) {
//
// Else if start of a literal ...
//
char c = LcData.subXlate(prevChr, pLocal, pMask); // cases
// like MM-
while (chrCnt-- > 0) {
sBuf.append(c);
}
if (chr == '?' || chr == '*' || chr == '+') {
sBuf.append(' ');
} else {
sBuf.append(chr);
}
chrCnt = 0;
prevChr = 0;
} else {
//
// Else yet another literal ...
//
if (chr == '?' || chr == '*' || chr == '+') {
sBuf.append(' ');
} else {
sBuf.append(chr);
}
prevChr = 0;
}
}
if (inQuoteQuoted) {
//
// Ensure quoted string is terminated.
//
inQuoted = false;
}
if (inQuoted) {
sBuf.setLength(0);
}
if (prevChr > 0 && chrCnt > 0) {
//
// Translate any remaining items in the pattern.
//
char c = LcData.subXlate(prevChr, pLocal, pMask);
while (chrCnt-- > 0) {
sBuf.append(c);
}
}
return sBuf.toString();
}
private static char subXlate(char c, String pPat, String pMask) {
assert (pPat != null && pMask != null);
assert (pPat.length() == pMask.length());
if (c == ' ') {
return c;
}
int index = pMask.indexOf(c);
if (index >= 0) {
return pPat.charAt(index);
}
return c;
}
/**
* Gets the thread-local store map. This is a convenience function that
* simply takes care of thread-local access and casting.
*
* @return The SortedMap object representing the thread-local store.
*/
private static final Map getMap() {
return mRuntimeMap.get();
}
}