< prev index next >
src/java.base/share/classes/java/util/Currency.java
Print this page
*** 151,187 ****
// 0 - simple country, bits 0-4 indicate final char of currency code
// - bits 5-8: fraction digits for simple countries, 0 for special cases
// - bits 0-4: final char for currency code for simple country, or ID of special case
// - special case IDs:
// - 0: country has no currency
! // - other: index into sc* arrays + 1
! // - scCutOverTimes: cut-over time in millis as returned by
! // System.currentTimeMillis for special case countries that are changing
! // currencies; Long.MAX_VALUE for countries that are not changing currencies
! // - scOldCurrencies: old currencies for special case countries
! // - scNewCurrencies: new currencies for special case countries that are
! // changing currencies; null for others
! // - scOldCurrenciesDFD: default fraction digits for old currencies
! // - scNewCurrenciesDFD: default fraction digits for new currencies, 0 for
! // countries that are not changing currencies
! // - otherCurrencies: concatenation of all currency codes that are not the
! // main currency of a simple country, separated by "-"
! // - otherCurrenciesDFD: decimal format digits for currencies in otherCurrencies, same order
static int formatVersion;
static int dataVersion;
static int[] mainTable;
! static long[] scCutOverTimes;
! static String[] scOldCurrencies;
! static String[] scNewCurrencies;
! static int[] scOldCurrenciesDFD;
! static int[] scNewCurrenciesDFD;
! static int[] scOldCurrenciesNumericCode;
! static int[] scNewCurrenciesNumericCode;
! static String otherCurrencies;
! static int[] otherCurrenciesDFD;
! static int[] otherCurrenciesNumericCode;
// handy constants - must match definitions in GenerateCurrencyData
// magic number
private static final int MAGIC_NUMBER = 0x43757244;
// number of characters from A to Z
--- 151,167 ----
// 0 - simple country, bits 0-4 indicate final char of currency code
// - bits 5-8: fraction digits for simple countries, 0 for special cases
// - bits 0-4: final char for currency code for simple country, or ID of special case
// - special case IDs:
// - 0: country has no currency
! // - other: index into specialCasesList
static int formatVersion;
static int dataVersion;
static int[] mainTable;
! static List<SpecialCaseEntry> specialCasesList;
! static List<OtherCurrencyEntry> otherCurrenciesList;
// handy constants - must match definitions in GenerateCurrencyData
// magic number
private static final int MAGIC_NUMBER = 0x43757244;
// number of characters from A to Z
*** 212,222 ****
private static final int NUMERIC_CODE_MASK = 0x000FFC00;
// shift count for the numeric code of the currency
private static final int NUMERIC_CODE_SHIFT = 10;
// Currency data format version
! private static final int VALID_FORMAT_VERSION = 2;
static {
AccessController.doPrivileged(new PrivilegedAction<>() {
@Override
public Void run() {
--- 192,202 ----
private static final int NUMERIC_CODE_MASK = 0x000FFC00;
// shift count for the numeric code of the currency
private static final int NUMERIC_CODE_SHIFT = 10;
// Currency data format version
! private static final int VALID_FORMAT_VERSION = 3;
static {
AccessController.doPrivileged(new PrivilegedAction<>() {
@Override
public Void run() {
*** 234,254 ****
throw new InternalError("Currency data format is incorrect");
}
dataVersion = dis.readInt();
mainTable = readIntArray(dis, A_TO_Z * A_TO_Z);
int scCount = dis.readInt();
! scCutOverTimes = readLongArray(dis, scCount);
! scOldCurrencies = readStringArray(dis, scCount);
! scNewCurrencies = readStringArray(dis, scCount);
! scOldCurrenciesDFD = readIntArray(dis, scCount);
! scNewCurrenciesDFD = readIntArray(dis, scCount);
! scOldCurrenciesNumericCode = readIntArray(dis, scCount);
! scNewCurrenciesNumericCode = readIntArray(dis, scCount);
int ocCount = dis.readInt();
! otherCurrencies = dis.readUTF();
! otherCurrenciesDFD = readIntArray(dis, ocCount);
! otherCurrenciesNumericCode = readIntArray(dis, ocCount);
}
} catch (IOException e) {
throw new InternalError(e);
}
--- 214,226 ----
throw new InternalError("Currency data format is incorrect");
}
dataVersion = dis.readInt();
mainTable = readIntArray(dis, A_TO_Z * A_TO_Z);
int scCount = dis.readInt();
! specialCasesList = readSpecialCases(dis, scCount);
int ocCount = dis.readInt();
! otherCurrenciesList = readOtherCurrencies(dis, ocCount);
}
} catch (IOException e) {
throw new InternalError(e);
}
*** 327,336 ****
--- 299,309 ----
if (defaultFractionDigits == Integer.MIN_VALUE) {
// Currency code not internally generated, need to verify first
// A currency code must have 3 characters and exist in the main table
// or in the list of other currencies.
+ boolean found = false;
if (currencyCode.length() != 3) {
throw new IllegalArgumentException();
}
char char1 = currencyCode.charAt(0);
char char2 = currencyCode.charAt(1);
*** 338,358 ****
if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
&& tableEntry != INVALID_COUNTRY_ENTRY
&& currencyCode.charAt(2) - 'A' == (tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK)) {
defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
! } else {
! // Check for '-' separately so we don't get false hits in the table.
! if (currencyCode.charAt(2) == '-') {
! throw new IllegalArgumentException();
}
! int index = otherCurrencies.indexOf(currencyCode);
! if (index == -1) {
throw new IllegalArgumentException();
}
! defaultFractionDigits = otherCurrenciesDFD[index / 4];
! numericCode = otherCurrenciesNumericCode[index / 4];
}
}
Currency currencyVal =
new Currency(currencyCode, defaultFractionDigits, numericCode);
--- 311,337 ----
if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
&& tableEntry != INVALID_COUNTRY_ENTRY
&& currencyCode.charAt(2) - 'A' == (tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK)) {
defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
! found = true;
! } else { //special case
! int[] fractionAndNumericCode = SpecialCaseEntry.findEntry(currencyCode);
! if (fractionAndNumericCode != null) {
! defaultFractionDigits = fractionAndNumericCode[0];
! numericCode = fractionAndNumericCode[1];
! found = true;
}
! }
!
! if (!found) {
! OtherCurrencyEntry ocEntry = OtherCurrencyEntry.findEntry(currencyCode);
! if (ocEntry == null) {
throw new IllegalArgumentException();
}
! defaultFractionDigits = ocEntry.fraction;
! numericCode = ocEntry.numericCode;
}
}
Currency currencyVal =
new Currency(currencyCode, defaultFractionDigits, numericCode);
*** 408,424 ****
throw new IllegalArgumentException();
}
if (tableEntry == COUNTRY_WITHOUT_CURRENCY_ENTRY) {
return null;
} else {
! int index = (tableEntry & SPECIAL_CASE_COUNTRY_INDEX_MASK) - SPECIAL_CASE_COUNTRY_INDEX_DELTA;
! if (scCutOverTimes[index] == Long.MAX_VALUE || System.currentTimeMillis() < scCutOverTimes[index]) {
! return getInstance(scOldCurrencies[index], scOldCurrenciesDFD[index],
! scOldCurrenciesNumericCode[index]);
} else {
! return getInstance(scNewCurrencies[index], scNewCurrenciesDFD[index],
! scNewCurrenciesNumericCode[index]);
}
}
}
}
--- 387,407 ----
throw new IllegalArgumentException();
}
if (tableEntry == COUNTRY_WITHOUT_CURRENCY_ENTRY) {
return null;
} else {
! int index = SpecialCaseEntry.toIndex(tableEntry);
! SpecialCaseEntry scEntry = specialCasesList.get(index);
! if (scEntry.cutOverTime == Long.MAX_VALUE
! || System.currentTimeMillis() < scEntry.cutOverTime) {
! return getInstance(scEntry.oldCurrency,
! scEntry.oldCurrencyFraction,
! scEntry.oldCurrencyNumericCode);
} else {
! return getInstance(scEntry.newCurrency,
! scEntry.newCurrencyFraction,
! scEntry.newCurrencyNumericCode);
}
}
}
}
*** 449,466 ****
StringBuilder sb = new StringBuilder();
sb.append(c1);
sb.append(c2);
sb.append(finalChar);
available.add(getInstance(sb.toString(), defaultFractionDigits, numericCode));
}
}
}
// Now add other currencies
! StringTokenizer st = new StringTokenizer(otherCurrencies, "-");
! while (st.hasMoreElements()) {
! available.add(getInstance((String)st.nextElement()));
}
}
}
@SuppressWarnings("unchecked")
--- 432,464 ----
StringBuilder sb = new StringBuilder();
sb.append(c1);
sb.append(c2);
sb.append(finalChar);
available.add(getInstance(sb.toString(), defaultFractionDigits, numericCode));
+ } else if ((tableEntry & COUNTRY_TYPE_MASK) == SPECIAL_CASE_COUNTRY_MASK
+ && tableEntry != INVALID_COUNTRY_ENTRY
+ && tableEntry != COUNTRY_WITHOUT_CURRENCY_ENTRY) {
+ int index = SpecialCaseEntry.toIndex(tableEntry);
+ SpecialCaseEntry scEntry = specialCasesList.get(index);
+
+ if (scEntry.cutOverTime == Long.MAX_VALUE
+ || System.currentTimeMillis() < scEntry.cutOverTime) {
+ available.add(getInstance(scEntry.oldCurrency,
+ scEntry.oldCurrencyFraction,
+ scEntry.oldCurrencyNumericCode));
+ } else {
+ available.add(getInstance(scEntry.newCurrency,
+ scEntry.newCurrencyFraction,
+ scEntry.newCurrencyNumericCode));
+ }
}
}
}
// Now add other currencies
! for (OtherCurrencyEntry entry : otherCurrenciesList) {
! available.add(getInstance(entry.currencyCode));
}
}
}
@SuppressWarnings("unchecked")
*** 691,716 ****
}
return ret;
}
! private static long[] readLongArray(DataInputStream dis, int count) throws IOException {
! long[] ret = new long[count];
! for (int i = 0; i < count; i++) {
! ret[i] = dis.readLong();
! }
! return ret;
! }
- private static String[] readStringArray(DataInputStream dis, int count) throws IOException {
- String[] ret = new String[count];
for (int i = 0; i < count; i++) {
! ret[i] = dis.readUTF();
}
!
! return ret;
}
/**
* Replaces currency data found in the currencydata.properties file
*
--- 689,747 ----
}
return ret;
}
! private static List<SpecialCaseEntry> readSpecialCases(DataInputStream dis,
! int count)
! throws IOException {
!
! List<SpecialCaseEntry> list = new ArrayList<>(count);
! long cutOverTime;
! String oldCurrency;
! String newCurrency;
! int oldCurrencyFraction;
! int newCurrencyFraction;
! int oldCurrencyNumericCode;
! int newCurrencyNumericCode;
! for (int i = 0; i < count; i++) {
! cutOverTime = dis.readLong();
! oldCurrency = dis.readUTF();
! newCurrency = dis.readUTF();
! oldCurrencyFraction = dis.readInt();
! newCurrencyFraction = dis.readInt();
! oldCurrencyNumericCode = dis.readInt();
! newCurrencyNumericCode = dis.readInt();
! SpecialCaseEntry sc = new SpecialCaseEntry(cutOverTime,
! oldCurrency, newCurrency,
! oldCurrencyFraction, newCurrencyFraction,
! oldCurrencyNumericCode, newCurrencyNumericCode);
! list.add(sc);
! }
! return list;
! }
!
! private static List<OtherCurrencyEntry> readOtherCurrencies(DataInputStream dis,
! int count)
! throws IOException {
!
! List<OtherCurrencyEntry> list = new ArrayList<>(count);
! String currencyCode;
! int fraction;
! int numericCode;
for (int i = 0; i < count; i++) {
! currencyCode = dis.readUTF();
! fraction = dis.readInt();
! numericCode = dis.readInt();
! OtherCurrencyEntry oc = new OtherCurrencyEntry(currencyCode,
! fraction,
! numericCode);
! list.add(oc);
}
! return list;
}
/**
* Replaces currency data found in the currencydata.properties file
*
*** 764,788 ****
" ignored since the fraction is more than " +
SIMPLE_CASE_COUNTRY_MAX_DEFAULT_DIGITS + ":" + curdata, null);
return;
}
! int index;
! for (index = 0; index < scOldCurrencies.length; index++) {
! if (scOldCurrencies[index].equals(code)) {
! break;
! }
}
! if (index == scOldCurrencies.length) {
// simple case
! entry |= (fraction << SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT) |
! (code.charAt(2) - 'A');
} else {
// special case
! entry |= SPECIAL_CASE_COUNTRY_MASK |
! (index + SPECIAL_CASE_COUNTRY_INDEX_DELTA);
}
setMainTableEntry(ctry.charAt(0), ctry.charAt(1), entry);
}
private static boolean isPastCutoverDate(String s) throws ParseException {
--- 795,825 ----
" ignored since the fraction is more than " +
SIMPLE_CASE_COUNTRY_MAX_DEFAULT_DIGITS + ":" + curdata, null);
return;
}
! int index = SpecialCaseEntry.indexOf(code, fraction, numeric);
!
! /* if a country switches from simple case to special case or
! * one special case to other special case which is not present
! * in the sc arrays then insert the new entry in special case arrays
! */
! if (index == -1 && (ctry.charAt(0) != code.charAt(0)
! || ctry.charAt(1) != code.charAt(1))) {
!
! specialCasesList.add(new SpecialCaseEntry(code, fraction, numeric));
! index = specialCasesList.size() - 1;
}
! if (index == -1) {
// simple case
! entry |= (fraction << SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT)
! | (code.charAt(2) - 'A');
} else {
// special case
! entry = SPECIAL_CASE_COUNTRY_MASK
! | (index + SPECIAL_CASE_COUNTRY_INDEX_DELTA);
}
setMainTableEntry(ctry.charAt(0), ctry.charAt(1), entry);
}
private static boolean isPastCutoverDate(String s) throws ParseException {
*** 812,818 ****
--- 849,978 ----
} else {
logger.info(message);
}
}
}
+
+ /* Used to represent a special case currency entry
+ * - cutOverTime: cut-over time in millis as returned by
+ * System.currentTimeMillis for special case countries that are changing
+ * currencies; Long.MAX_VALUE for countries that are not changing currencies
+ * - oldCurrency: old currencies for special case countries
+ * - newCurrency: new currencies for special case countries that are
+ * changing currencies; null for others
+ * - oldCurrencyFraction: default fraction digits for old currencies
+ * - newCurrencyFraction: default fraction digits for new currencies, 0 for
+ * countries that are not changing currencies
+ * - oldCurrencyNumericCode: numeric code for old currencies
+ * - newCurrencyNumericCode: numeric code for new currencies, 0 for countries
+ * that are not changing currencies
+ */
+ private static class SpecialCaseEntry {
+
+ final private long cutOverTime;
+ final private String oldCurrency;
+ final private String newCurrency;
+ final private int oldCurrencyFraction;
+ final private int newCurrencyFraction;
+ final private int oldCurrencyNumericCode;
+ final private int newCurrencyNumericCode;
+
+ private SpecialCaseEntry(long cutOverTime, String oldCurrency, String newCurrency,
+ int oldCurrencyFraction, int newCurrencyFraction,
+ int oldCurrencyNumericCode, int newCurrencyNumericCode) {
+ this.cutOverTime = cutOverTime;
+ this.oldCurrency = oldCurrency;
+ this.newCurrency = newCurrency;
+ this.oldCurrencyFraction = oldCurrencyFraction;
+ this.newCurrencyFraction = newCurrencyFraction;
+ this.oldCurrencyNumericCode = oldCurrencyNumericCode;
+ this.newCurrencyNumericCode = newCurrencyNumericCode;
+ }
+
+ private SpecialCaseEntry(String currencyCode, int fraction,
+ int numericCode) {
+ this(Long.MAX_VALUE, currencyCode, "", fraction, 0, numericCode, 0);
+ }
+
+ //get the index of the special case entry
+ private static int indexOf(String code, int fraction, int numeric) {
+ int size = specialCasesList.size();
+ for (int index = 0; index < size; index++) {
+ SpecialCaseEntry scEntry = specialCasesList.get(index);
+ if (scEntry.oldCurrency.equals(code)
+ && scEntry.oldCurrencyFraction == fraction
+ && scEntry.oldCurrencyNumericCode == numeric
+ && scEntry.cutOverTime == Long.MAX_VALUE) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ // get the fraction and numericCode of the sc currencycode
+ private static int[] findEntry(String code) {
+ int[] fractionAndNumericCode = null;
+ int size = specialCasesList.size();
+ for (int index = 0; index < size; index++) {
+ SpecialCaseEntry scEntry = specialCasesList.get(index);
+ if (scEntry.oldCurrency.equals(code) && (scEntry.cutOverTime == Long.MAX_VALUE
+ || System.currentTimeMillis() < scEntry.cutOverTime)) {
+ //consider only when there is no new currency or cutover time is not passed
+ fractionAndNumericCode = new int[2];
+ fractionAndNumericCode[0] = scEntry.oldCurrencyFraction;
+ fractionAndNumericCode[1] = scEntry.oldCurrencyNumericCode;
+ break;
+ } else if (scEntry.newCurrency.equals(code)
+ && System.currentTimeMillis() >= scEntry.cutOverTime) {
+ //consider only if the cutover time is passed
+ fractionAndNumericCode = new int[2];
+ fractionAndNumericCode[0] = scEntry.newCurrencyFraction;
+ fractionAndNumericCode[1] = scEntry.newCurrencyNumericCode;
+ break;
+ }
+ }
+ return fractionAndNumericCode;
+ }
+
+ // convert the special case entry to sc arrays index
+ private static int toIndex(int tableEntry) {
+ return (tableEntry & SPECIAL_CASE_COUNTRY_INDEX_MASK) - SPECIAL_CASE_COUNTRY_INDEX_DELTA;
+ }
+
+ }
+
+ /* Used to represent Other currencies
+ * - currencyCode: currency codes that are not the main currency
+ * of a simple country
+ * - otherCurrenciesDFD: decimal format digits for other currencies
+ * - otherCurrenciesNumericCode: numeric code for other currencies
+ */
+ private static class OtherCurrencyEntry {
+
+ final private String currencyCode;
+ final private int fraction;
+ final private int numericCode;
+
+ private OtherCurrencyEntry(String currencyCode, int fraction,
+ int numericCode) {
+ this.currencyCode = currencyCode;
+ this.fraction = fraction;
+ this.numericCode = numericCode;
+ }
+
+ //get the instance of the other currency code
+ private static OtherCurrencyEntry findEntry(String code) {
+ int size = otherCurrenciesList.size();
+ for (int index = 0; index < size; index++) {
+ OtherCurrencyEntry ocEntry = otherCurrenciesList.get(index);
+ if (ocEntry.currencyCode.equalsIgnoreCase(code)) {
+ return ocEntry;
+ }
+ }
+ return null;
+ }
+
+ }
+
}
+
< prev index next >