/*
* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.util;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.Serializable;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.logging.Level;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.spi.CurrencyNameProvider;
import java.util.spi.LocaleServiceProvider;
import sun.util.LocaleServiceProviderPool;
import sun.util.logging.PlatformLogger;
import sun.util.resources.LocaleData;
import sun.util.resources.OpenListResourceBundle;
/**
* Represents a currency. Currencies are identified by their ISO 4217 currency
* codes. Visit the
* ISO web site for more information, including a table of
* currency codes.
*
* The class is designed so that there's never more than one
* Currency instance for any given currency. Therefore, there's
* no public constructor. You obtain a Currency instance using
* the getInstance methods.
*
* Users can supersede the Java runtime currency data by creating a properties
* file named <JAVA_HOME>/lib/currency.properties. The contents
* of the properties file are key/value pairs of the ISO 3166 country codes
* and the ISO 4217 currency data respectively. The value part consists of
* three ISO 4217 values of a currency, i.e., an alphabetic code, a numeric
* code, and a minor unit. Those three ISO 4217 values are separated by commas.
* The lines which start with '#'s are considered comment lines. For example,
*
* will supersede the currency data for Japan.
*
* @since 1.4
*/
public final class Currency implements Serializable {
private static final long serialVersionUID = -158308464356906721L;
/**
* ISO 4217 currency code for this currency.
*
* @serial
*/
private final String currencyCode;
/**
* Default fraction digits for this currency.
* Set from currency data tables.
*/
transient private final int defaultFractionDigits;
/**
* ISO 4217 numeric code for this currency.
* Set from currency data tables.
*/
transient private final int numericCode;
// class data: instance map
private static HashMap instances = new HashMap(7);
private static HashSet available;
// Class data: currency data obtained from currency.data file.
// Purpose:
// - determine valid country codes
// - determine valid currency codes
// - map country codes to currency codes
// - obtain default fraction digits for currency codes
//
// sc = special case; dfd = default fraction digits
// Simple countries are those where the country code is a prefix of the
// currency code, and there are no known plans to change the currency.
//
// table formats:
// - mainTable:
// - maps country code to 32-bit int
// - 26*26 entries, corresponding to [A-Z]*[A-Z]
// - \u007F -> not valid country
// - bits 18-31: unused
// - bits 8-17: numeric code (0 to 1023)
// - bit 7: 1 - special case, bits 0-4 indicate which one
// 0 - simple country, bits 0-4 indicate final char of currency code
// - bits 5-6: 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
private static final int A_TO_Z = ('Z' - 'A') + 1;
// entry for invalid country codes
private static final int INVALID_COUNTRY_ENTRY = 0x007F;
// entry for countries without currency
private static final int COUNTRY_WITHOUT_CURRENCY_ENTRY = 0x0080;
// mask for simple case country entries
private static final int SIMPLE_CASE_COUNTRY_MASK = 0x0000;
// mask for simple case country entry final character
private static final int SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK = 0x001F;
// mask for simple case country entry default currency digits
private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK = 0x0060;
// shift count for simple case country entry default currency digits
private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT = 5;
// mask for special case country entries
private static final int SPECIAL_CASE_COUNTRY_MASK = 0x0080;
// mask for special case country index
private static final int SPECIAL_CASE_COUNTRY_INDEX_MASK = 0x001F;
// delta from entry index component in main table to index into special case tables
private static final int SPECIAL_CASE_COUNTRY_INDEX_DELTA = 1;
// mask for distinguishing simple and special case countries
private static final int COUNTRY_TYPE_MASK = SIMPLE_CASE_COUNTRY_MASK | SPECIAL_CASE_COUNTRY_MASK;
// mask for the numeric code of the currency
private static final int NUMERIC_CODE_MASK = 0x0003FF00;
// shift count for the numeric code of the currency
private static final int NUMERIC_CODE_SHIFT = 8;
// Currency data format version
private static final int VALID_FORMAT_VERSION = 1;
static {
AccessController.doPrivileged(new PrivilegedAction