]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/ucurr.cpp
ICU-400.37.tar.gz
[apple/icu.git] / icuSources / i18n / ucurr.cpp
index 4eb42de4890bf256c06ad9d5f83e39a61ab5bc8d..7705a5bd8d209e60d1080368c7cd46021b34404f 100644 (file)
@@ -1,6 +1,6 @@
 /*
 **********************************************************************
-* Copyright (c) 2002-2003, International Business Machines
+* Copyright (c) 2002-2008, International Business Machines
 * Corporation and others.  All Rights Reserved.
 **********************************************************************
 */
 
 #include "unicode/ucurr.h"
 #include "unicode/locid.h"
-#include "unicode/resbund.h"
+#include "unicode/ures.h"
 #include "unicode/ustring.h"
+#include "unicode/choicfmt.h"
+#include "unicode/parsepos.h"
+#include "ustr_imp.h"
 #include "cmemory.h"
 #include "cstring.h"
 #include "uassert.h"
-#include "iculserv.h"
+#include "umutex.h"
 #include "ucln_in.h"
+#include "uenumimp.h"
+#include "uresimp.h"
 
 //------------------------------------------------------------
 // Constants
@@ -38,7 +43,9 @@ static const int32_t MAX_POW10 = (sizeof(POW10)/sizeof(POW10[0])) - 1;
 
 //------------------------------------------------------------
 // Resource tags
+//
 
+static const char CURRENCY_DATA[] = "supplementalData";
 // Tag for meta-data, in root.
 static const char CURRENCY_META[] = "CurrencyMeta";
 
@@ -55,7 +62,15 @@ static const char VAR_PRE_EURO[] = "PREEURO";
 static const char VAR_EURO[] = "EURO";
 
 // Variant delimiter
-static const char VAR_DELIM[] = "_";
+static const char VAR_DELIM = '_';
+static const char VAR_DELIM_STR[] = "_";
+
+// Variant for legacy euro mapping in CurrencyMap
+//static const char VAR_DELIM_EURO[] = "_EURO";
+
+#define VARIANT_IS_EMPTY    0
+#define VARIANT_IS_EURO     0x1
+#define VARIANT_IS_PREEURO  0x2
 
 // Tag for localized display names (symbols) of currencies
 static const char CURRENCIES[] = "Currencies";
@@ -66,6 +81,8 @@ static const char CURRENCIES[] = "Currencies";
 // the first mark is deleted.
 static const UChar CHOICE_FORMAT_MARK = 0x003D; // Equals sign
 
+static const UChar EUR_STR[] = {0x0045,0x0055,0x0052,0};
+
 //------------------------------------------------------------
 // Code
 
@@ -87,41 +104,86 @@ myUCharsToChars(char* resultOfLen4, const UChar* currency) {
  * units of 10^(-fraction_digits).
  */
 static const int32_t*
-_findMetaData(const UChar* currency) {
+_findMetaData(const UChar* currency, UErrorCode& ec) {
+
+    if (currency == 0 || *currency == 0) {
+        if (U_SUCCESS(ec)) {
+            ec = U_ILLEGAL_ARGUMENT_ERROR;
+        }
+        return LAST_RESORT_DATA;
+    }
 
     // Get CurrencyMeta resource out of root locale file.  [This may
     // move out of the root locale file later; if it does, update this
     // code.]
-    UErrorCode ec = U_ZERO_ERROR;
-    ResourceBundle currencyMeta =
-        ResourceBundle((char*)0, Locale(""), ec).get(CURRENCY_META, ec);
-    
+    UResourceBundle* currencyData = ures_openDirect(NULL, CURRENCY_DATA, &ec);
+    UResourceBundle* currencyMeta = ures_getByKey(currencyData, CURRENCY_META, currencyData, &ec);
+
     if (U_FAILURE(ec)) {
+        ures_close(currencyMeta);
         // Config/build error; return hard-coded defaults
         return LAST_RESORT_DATA;
     }
 
     // Look up our currency, or if that's not available, then DEFAULT
     char buf[ISO_COUNTRY_CODE_LENGTH+1];
-    ResourceBundle rb = currencyMeta.get(myUCharsToChars(buf, currency), ec);
-    if (U_FAILURE(ec)) {
-        rb = currencyMeta.get(DEFAULT_META, ec);
+    UErrorCode ec2 = U_ZERO_ERROR; // local error code: soft failure
+    UResourceBundle* rb = ures_getByKey(currencyMeta, myUCharsToChars(buf, currency), NULL, &ec2);
+      if (U_FAILURE(ec2)) {
+        ures_close(rb);
+        rb = ures_getByKey(currencyMeta,DEFAULT_META, NULL, &ec);
         if (U_FAILURE(ec)) {
+            ures_close(currencyMeta);
+            ures_close(rb);
             // Config/build error; return hard-coded defaults
             return LAST_RESORT_DATA;
         }
     }
 
     int32_t len;
-    const int32_t *data = rb.getIntVector(len, ec);
-    if (U_FAILURE(ec) || len < 2) {
+    const int32_t *data = ures_getIntVector(rb, &len, &ec);
+    if (U_FAILURE(ec) || len != 2) {
         // Config/build error; return hard-coded defaults
+        if (U_SUCCESS(ec)) {
+            ec = U_INVALID_FORMAT_ERROR;
+        }
+        ures_close(currencyMeta);
+        ures_close(rb);
         return LAST_RESORT_DATA;
     }
 
+    ures_close(currencyMeta);
+    ures_close(rb);
     return data;
 }
 
+// -------------------------------------
+
+/**
+ * @see VARIANT_IS_EURO
+ * @see VARIANT_IS_PREEURO
+ */
+static uint32_t
+idForLocale(const char* locale, char* countryAndVariant, int capacity, UErrorCode* ec)
+{
+    uint32_t variantType = 0;
+    // !!! this is internal only, assumes buffer is not null and capacity is sufficient
+    // Extract the country name and variant name.  We only
+    // recognize two variant names, EURO and PREEURO.
+    char variant[ULOC_FULLNAME_CAPACITY];
+    uloc_getCountry(locale, countryAndVariant, capacity, ec);
+    uloc_getVariant(locale, variant, sizeof(variant), ec);
+    if (variant[0] != 0) {
+        variantType = (0 == uprv_strcmp(variant, VAR_EURO))
+                   | ((0 == uprv_strcmp(variant, VAR_PRE_EURO)) << 1);
+        if (variantType)
+        {
+            uprv_strcat(countryAndVariant, VAR_DELIM_STR);
+            uprv_strcat(countryAndVariant, variant);
+        }
+    }
+    return variantType;
+}
 
 // ------------------------------------------
 //
@@ -131,21 +193,25 @@ _findMetaData(const UChar* currency) {
 
 // don't use ICUService since we don't need fallback
 
+#if !UCONFIG_NO_SERVICE
+U_CDECL_BEGIN
+static UBool U_CALLCONV currency_cleanup(void);
+U_CDECL_END
 struct CReg;
 
 /* Remember to call umtx_init(&gCRegLock) before using it! */
 static UMTX gCRegLock = 0;
 static CReg* gCRegHead = 0;
 
-struct CReg : public UMemory {
+struct CReg : public U_NAMESPACE_QUALIFIER UMemory {
     CReg *next;
     UChar iso[ISO_COUNTRY_CODE_LENGTH+1];
     char  id[ULOC_FULLNAME_CAPACITY];
-    
+
     CReg(const UChar* _iso, const char* _id)
         : next(0)
     {
-        int32_t len = uprv_strlen(_id);
+        int32_t len = (int32_t)uprv_strlen(_id);
         if (len > (int32_t)(sizeof(id)-1)) {
             len = (sizeof(id)-1);
         }
@@ -154,59 +220,65 @@ struct CReg : public UMemory {
         uprv_memcpy(iso, _iso, ISO_COUNTRY_CODE_LENGTH * sizeof(const UChar));
         iso[ISO_COUNTRY_CODE_LENGTH] = 0;
     }
-    
+
     static UCurrRegistryKey reg(const UChar* _iso, const char* _id, UErrorCode* status)
     {
         if (status && U_SUCCESS(*status) && _iso && _id) {
             CReg* n = new CReg(_iso, _id);
             if (n) {
                 umtx_init(&gCRegLock);
-                Mutex mutex(&gCRegLock);
+                umtx_lock(&gCRegLock);
                 if (!gCRegHead) {
-                    ucln_i18n_registerCleanup();
+                    /* register for the first time */
+                    ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
                 }
                 n->next = gCRegHead;
                 gCRegHead = n;
+                umtx_unlock(&gCRegLock);
                 return n;
             }
             *status = U_MEMORY_ALLOCATION_ERROR;
         }
         return 0;
     }
-    
+
     static UBool unreg(UCurrRegistryKey key) {
+        UBool found = FALSE;
         umtx_init(&gCRegLock);
-        Mutex mutex(&gCRegLock);
-        if (gCRegHead == key) {
-            gCRegHead = gCRegHead->next;
-            delete (CReg*)key;
-            return TRUE;
-        }
-        
-        CReg* p = gCRegHead;
-        while (p) {
-            if (p->next == key) {
-                p->next = ((CReg*)key)->next;
-                delete (CReg*)key;     
-                return TRUE;
+        umtx_lock(&gCRegLock);
+
+        CReg** p = &gCRegHead;
+        while (*p) {
+            if (*p == key) {
+                *p = ((CReg*)key)->next;
+                delete (CReg*)key;
+                found = TRUE;
+                break;
             }
-            p = p->next;
+            p = &((*p)->next);
         }
-        
-        return FALSE;
+
+        umtx_unlock(&gCRegLock);
+        return found;
     }
-    
+
     static const UChar* get(const char* id) {
+        const UChar* result = NULL;
         umtx_init(&gCRegLock);
-        Mutex mutex(&gCRegLock);
+        umtx_lock(&gCRegLock);
         CReg* p = gCRegHead;
+
+        /* register cleanup of the mutex */
+        ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
         while (p) {
             if (uprv_strcmp(id, p->id) == 0) {
-                return p->iso;
+                result = p->iso;
+                break;
             }
             p = p->next;
         }
-        return NULL;
+        umtx_unlock(&gCRegLock);
+        return result;
     }
 
     /* This doesn't need to be thread safe. It's for u_cleanup only. */
@@ -220,29 +292,22 @@ struct CReg : public UMemory {
     }
 };
 
-// -------------------------------------
-
-static void
-idForLocale(const char* locale, char* buffer, int capacity, UErrorCode* ec)
-{
-    // !!! this is internal only, assumes buffer is not null and capacity is sufficient
-    // Extract the country name and variant name.  We only
-    // recognize two variant names, EURO and PREEURO.
-    char variant[ULOC_FULLNAME_CAPACITY];
-    uloc_getCountry(locale, buffer, capacity, ec);
-    uloc_getVariant(locale, variant, sizeof(variant), ec);
-    if (0 == uprv_strcmp(variant, VAR_PRE_EURO) ||
-        0 == uprv_strcmp(variant, VAR_EURO))
-    {
-        uprv_strcat(buffer, VAR_DELIM);
-        uprv_strcat(buffer, variant);
-    }
+/**
+ * Release all static memory held by currency.
+ */
+U_CDECL_BEGIN
+static UBool U_CALLCONV currency_cleanup(void) {
+#if !UCONFIG_NO_SERVICE
+    CReg::cleanup();
+#endif
+    return TRUE;
 }
+U_CDECL_END
 
 // -------------------------------------
 
 U_CAPI UCurrRegistryKey U_EXPORT2
-ucurr_register(const UChar* isoCode, const char* locale, UErrorCode *status) 
+ucurr_register(const UChar* isoCode, const char* locale, UErrorCode *status)
 {
     if (status && U_SUCCESS(*status)) {
         char id[ULOC_FULLNAME_CAPACITY];
@@ -255,43 +320,106 @@ ucurr_register(const UChar* isoCode, const char* locale, UErrorCode *status)
 // -------------------------------------
 
 U_CAPI UBool U_EXPORT2
-ucurr_unregister(UCurrRegistryKey key, UErrorCode* status) 
+ucurr_unregister(UCurrRegistryKey key, UErrorCode* status)
 {
     if (status && U_SUCCESS(*status)) {
         return CReg::unreg(key);
     }
     return FALSE;
 }
+#endif /* UCONFIG_NO_SERVICE */
 
 // -------------------------------------
 
-U_CAPI const UChar* U_EXPORT2
-ucurr_forLocale(const char* locale, UErrorCode* ec) {
+U_CAPI int32_t U_EXPORT2
+ucurr_forLocale(const char* locale,
+                UChar* buff,
+                int32_t buffCapacity,
+                UErrorCode* ec)
+{
+    int32_t resLen = 0;
+    const UChar* s = NULL;
     if (ec != NULL && U_SUCCESS(*ec)) {
-        char id[ULOC_FULLNAME_CAPACITY];
-        idForLocale(locale, id, sizeof(id), ec);
-        if (U_FAILURE(*ec)) {
-            return NULL;
-        }
-        
-        const UChar* result = CReg::get(id);
-        if (result) {
-            return result;
-        }
-        
-        // Look up the CurrencyMap element in the root bundle.
-        UResourceBundle* rb = ures_open(NULL, "", ec);
-        UResourceBundle* cm = ures_getByKey(rb, CURRENCY_MAP, NULL, ec);
-        int32_t len;
-        const UChar* s = ures_getStringByKey(cm, id, &len, ec);
-        ures_close(cm);
-        ures_close(rb);
-        
-        if (U_SUCCESS(*ec)) {
-            return s;
+        if ((buff && buffCapacity) || !buffCapacity) {
+            UErrorCode localStatus = U_ZERO_ERROR;
+            char id[ULOC_FULLNAME_CAPACITY];
+            if ((resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus))) {
+                // there is a currency keyword. Try to see if it's valid
+                if(buffCapacity > resLen) {
+                    u_charsToUChars(id, buff, resLen);
+                }
+            } else {
+                // get country or country_variant in `id'
+                uint32_t variantType = idForLocale(locale, id, sizeof(id), ec);
+
+                if (U_FAILURE(*ec)) {
+                    return 0;
+                }
+
+#if !UCONFIG_NO_SERVICE
+                const UChar* result = CReg::get(id);
+                if (result) {
+                    if(buffCapacity > u_strlen(result)) {
+                        u_strcpy(buff, result);
+                    }
+                    return u_strlen(result);
+                }
+#endif
+                // Remove variants, which is only needed for registration.
+                char *idDelim = strchr(id, VAR_DELIM);
+                if (idDelim) {
+                    idDelim[0] = 0;
+                }
+
+                // Look up the CurrencyMap element in the root bundle.
+                UResourceBundle *rb = ures_openDirect(NULL, CURRENCY_DATA, &localStatus);
+                UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
+                UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
+                UResourceBundle *currencyReq = ures_getByIndex(countryArray, 0, NULL, &localStatus);
+                s = ures_getStringByKey(currencyReq, "id", &resLen, &localStatus);
+
+                /*
+                Get the second item when PREEURO is requested, and this is a known Euro country.
+                If the requested variant is PREEURO, and this isn't a Euro country, assume
+                that the country changed over to the Euro in the future. This is probably
+                an old version of ICU that hasn't been updated yet. The latest currency is
+                probably correct.
+                */
+                if (U_SUCCESS(localStatus)) {
+                    if ((variantType & VARIANT_IS_PREEURO) && u_strcmp(s, EUR_STR) == 0) {
+                        currencyReq = ures_getByIndex(countryArray, 1, currencyReq, &localStatus);
+                        s = ures_getStringByKey(currencyReq, "id", &resLen, &localStatus);
+                    }
+                    else if ((variantType & VARIANT_IS_EURO)) {
+                        s = EUR_STR;
+                    }
+                }
+                ures_close(countryArray);
+                ures_close(currencyReq);
+
+                if ((U_FAILURE(localStatus)) && strchr(id, '_') != 0)
+                {
+                    // We don't know about it.  Check to see if we support the variant.
+                    uloc_getParent(locale, id, sizeof(id), ec);
+                    *ec = U_USING_FALLBACK_WARNING;
+                    return ucurr_forLocale(id, buff, buffCapacity, ec);
+                }
+                else if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR) {
+                    // There is nothing to fallback to. Report the failure/warning if possible.
+                    *ec = localStatus;
+                }
+                if (U_SUCCESS(*ec)) {
+                    if(buffCapacity > resLen) {
+                        u_strcpy(buff, s);
+                    }
+                }
+            }
+            return u_terminateUChars(buff, buffCapacity, resLen, ec);
+        } else {
+            *ec = U_ILLEGAL_ARGUMENT_ERROR;
         }
     }
-    return NULL;
+    return resLen;
 }
 
 // end registration
@@ -308,7 +436,7 @@ static UBool fallback(char *loc) {
         return FALSE;
     }
     UErrorCode status = U_ZERO_ERROR;
-    uloc_getParent(loc, loc, uprv_strlen(loc), &status);
+    uloc_getParent(loc, loc, (int32_t)uprv_strlen(loc), &status);
  /*
     char *i = uprv_strrchr(loc, '_');
     if (i == NULL) {
@@ -331,7 +459,7 @@ ucurr_getName(const UChar* currency,
     // Look up the Currencies resource for the given locale.  The
     // Currencies locale data looks like this:
     //|en {
-    //|  Currencies { 
+    //|  Currencies {
     //|    USD { "US$", "US Dollar" }
     //|    CHF { "Sw F", "Swiss Franc" }
     //|    INR { "=0#Rs|1#Re|1<Rs", "=0#Rupees|1#Rupee|1<Rupees" }
@@ -339,7 +467,7 @@ ucurr_getName(const UChar* currency,
     //|  }
     //|}
 
-    if (ec == NULL || U_FAILURE(*ec)) {
+    if (U_FAILURE(*ec)) {
         return 0;
     }
 
@@ -348,7 +476,7 @@ ucurr_getName(const UChar* currency,
         *ec = U_ILLEGAL_ARGUMENT_ERROR;
         return 0;
     }
-    
+
     // In the future, resource bundles may implement multi-level
     // fallback.  That is, if a currency is not found in the en_US
     // Currencies data, then the en Currencies data will be searched.
@@ -373,22 +501,23 @@ ucurr_getName(const UChar* currency,
     myUCharsToChars(buf, currency);
 
     const UChar* s = NULL;
+    ec2 = U_ZERO_ERROR;
+    UResourceBundle* rb = ures_open(NULL, loc, &ec2);
 
-    // Multi-level resource inheritance fallback loop
-    for (;;) {
-        ec2 = U_ZERO_ERROR;
-        UResourceBundle* rb = ures_open(NULL, loc, &ec2);
-        UResourceBundle* curr = ures_getByKey(rb, CURRENCIES, NULL, &ec2);
-        UResourceBundle* names = ures_getByKey(curr, buf, NULL, &ec2);
-        s = ures_getStringByIndex(names, choice, len, &ec2);
-        ures_close(names);
-        ures_close(curr);
-        ures_close(rb);
+    rb = ures_getByKey(rb, CURRENCIES, rb, &ec2);
 
-        // If we've succeeded we're done.  Otherwise, try to fallback.
-        // If that fails (because we are already at root) then exit.
-        if (U_SUCCESS(ec2) || !fallback(loc)) {
-            break;
+    // Fetch resource with multi-level resource inheritance fallback
+    rb = ures_getByKeyWithFallback(rb, buf, rb, &ec2);
+
+    s = ures_getStringByIndex(rb, choice, len, &ec2);
+    ures_close(rb);
+
+    // If we've succeeded we're done.  Otherwise, try to fallback.
+    // If that fails (because we are already at root) then exit.
+    if (U_SUCCESS(ec2)) {
+        if (ec2 == U_USING_DEFAULT_WARNING
+            || (ec2 == U_USING_FALLBACK_WARNING && *ec != U_USING_DEFAULT_WARNING)) {
+            *ec = ec2;
         }
     }
 
@@ -411,40 +540,197 @@ ucurr_getName(const UChar* currency,
 
     // If we fail to find a match, use the ISO 4217 code
     *len = u_strlen(currency); // Should == ISO_COUNTRY_CODE_LENGTH, but maybe not...?
+    *ec = U_USING_DEFAULT_WARNING;
     return currency;
 }
 
-//!// This API is now redundant.  It predates ucurr_getName, which
-//!// replaces and extends it.
-//!U_CAPI const UChar* U_EXPORT2
-//!ucurr_getSymbol(const UChar* currency,
-//!                const char* locale,
-//!    int32_t* len, // fillin
-//!                UErrorCode* ec) {
-//!    UBool isChoiceFormat;
-//!    const UChar* s = ucurr_getName(currency, locale, UCURR_SYMBOL_NAME,
-//!                                   &isChoiceFormat, len, ec);
-//!    if (isChoiceFormat) {
-//!        // Don't let ChoiceFormat patterns out through this API
-//!        *len = u_strlen(currency); // Should == 3, but maybe not...?
-//!        return currency;
-//!    }
-//!    return s;
-//!}
+U_CFUNC void
+uprv_parseCurrency(const char* locale,
+                   const U_NAMESPACE_QUALIFIER UnicodeString& text,
+                   U_NAMESPACE_QUALIFIER ParsePosition& pos,
+                   UChar* result,
+                   UErrorCode& ec)
+{
+    U_NAMESPACE_USE
+
+    // TODO: There is a slight problem with the pseudo-multi-level
+    // fallback implemented here.  More-specific locales don't
+    // properly shield duplicate entries in less-specific locales.
+    // This problem will go away when real multi-level fallback is
+    // implemented.  We could also fix this by recording (in a
+    // hash) which codes are used at each level of fallback, but
+    // this doesn't seem warranted.
+
+    if (U_FAILURE(ec)) {
+        return;
+    }
+
+    // Look up the Currencies resource for the given locale.  The
+    // Currencies locale data looks like this:
+    //|en {
+    //|  Currencies {
+    //|    USD { "US$", "US Dollar" }
+    //|    CHF { "Sw F", "Swiss Franc" }
+    //|    INR { "=0#Rs|1#Re|1<Rs", "=0#Rupees|1#Rupee|1<Rupees" }
+    //|    //...
+    //|  }
+    //|}
+
+    // In the future, resource bundles may implement multi-level
+    // fallback.  That is, if a currency is not found in the en_US
+    // Currencies data, then the en Currencies data will be searched.
+    // Currently, if a Currencies datum exists in en_US and en, the
+    // en_US entry hides that in en.
+
+    // We want multi-level fallback for this resource, so we implement
+    // it manually.
+
+    // Use a separate UErrorCode here that does not propagate out of
+    // this function.
+    UErrorCode ec2 = U_ZERO_ERROR;
+
+    char loc[ULOC_FULLNAME_CAPACITY];
+    uloc_getName(locale, loc, sizeof(loc), &ec2);
+    if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
+        ec = U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    int32_t start = pos.getIndex();
+    const UChar* s = NULL;
+
+    const char* iso = NULL;
+    int32_t max = 0;
+
+    // Multi-level resource inheritance fallback loop
+    for (;;) {
+        ec2 = U_ZERO_ERROR;
+        UResourceBundle* rb = ures_open(NULL, loc, &ec2);
+        UResourceBundle* curr = ures_getByKey(rb, CURRENCIES, NULL, &ec2);
+        int32_t n = ures_getSize(curr);
+        for (int32_t i=0; i<n; ++i) {
+            UResourceBundle* names = ures_getByIndex(curr, i, NULL, &ec2);
+            int32_t len;
+            s = ures_getStringByIndex(names, UCURR_SYMBOL_NAME, &len, &ec2);
+            UBool isChoice = FALSE;
+            if (len > 0 && s[0] == CHOICE_FORMAT_MARK) {
+                ++s;
+                --len;
+                if (len > 0 && s[0] != CHOICE_FORMAT_MARK) {
+                    isChoice = TRUE;
+                }
+            }
+            if (isChoice) {
+                Formattable temp;
+                ChoiceFormat fmt(s, ec2);
+                fmt.parse(text, temp, pos);
+                len = pos.getIndex() - start;
+                pos.setIndex(start);
+            } else if (len > max &&
+                       text.compare(pos.getIndex(), len, s) != 0) {
+                len = 0;
+            }
+            if (len > max) {
+                iso = ures_getKey(names);
+                max = len;
+            }
+            ures_close(names);
+        }
+        ures_close(curr);
+        ures_close(rb);
+
+        // Try to fallback.  If that fails (because we are already at
+        // root) then exit.
+        if (!fallback(loc)) {
+            break;
+        }
+    }
+
+    if (iso != NULL) {
+        u_charsToUChars(iso, result, 4);
+    }
+
+    // If display name parse fails or if it matches fewer than 3
+    // characters, try to parse 3-letter ISO.  Do this after the
+    // display name processing so 3-letter display names are
+    // preferred.  Consider /[A-Z]{3}/ to be valid ISO, and parse
+    // it manually--UnicodeSet/regex are too slow and heavy.
+    if (max < 3 && (text.length() - start) >= 3) {
+        UBool valid = TRUE;
+        for (int32_t k=0; k<3; ++k) {
+            UChar ch = text.charAt(start + k); // 16-bit ok
+            if (ch < 0x41/*'A'*/ || ch > 0x5A/*'Z'*/) {
+                valid = FALSE;
+                break;
+            }
+        }
+        if (valid) {
+            text.extract(start, 3, result);
+            result[3] = 0;
+            max = 3;
+        }
+    }
+
+    pos.setIndex(start + max);
+}
+
+/**
+ * Internal method.  Given a currency ISO code and a locale, return
+ * the "static" currency name.  This is usually the same as the
+ * UCURR_SYMBOL_NAME, but if the latter is a choice format, then the
+ * format is applied to the number 2.0 (to yield the more common
+ * plural) to return a static name.
+ *
+ * This is used for backward compatibility with old currency logic in
+ * DecimalFormat and DecimalFormatSymbols.
+ */
+U_CFUNC void
+uprv_getStaticCurrencyName(const UChar* iso, const char* loc,
+                           U_NAMESPACE_QUALIFIER UnicodeString& result, UErrorCode& ec)
+{
+    U_NAMESPACE_USE
+
+    UBool isChoiceFormat;
+    int32_t len;
+    const UChar* currname = ucurr_getName(iso, loc, UCURR_SYMBOL_NAME,
+                                          &isChoiceFormat, &len, &ec);
+    if (U_SUCCESS(ec)) {
+        // If this is a ChoiceFormat currency, then format an
+        // arbitrary value; pick something != 1; more common.
+        result.truncate(0);
+        if (isChoiceFormat) {
+            ChoiceFormat f(currname, ec);
+            if (U_SUCCESS(ec)) {
+                f.format(2.0, result);
+            } else {
+                result = iso;
+            }
+        } else {
+            result = currname;
+        }
+    }
+}
 
 U_CAPI int32_t U_EXPORT2
-ucurr_getDefaultFractionDigits(const UChar* currency) {
-    return (_findMetaData(currency))[0];
+ucurr_getDefaultFractionDigits(const UChar* currency, UErrorCode* ec) {
+    return (_findMetaData(currency, *ec))[0];
 }
 
 U_CAPI double U_EXPORT2
-ucurr_getRoundingIncrement(const UChar* currency) {
-    const int32_t *data = _findMetaData(currency);
+ucurr_getRoundingIncrement(const UChar* currency, UErrorCode* ec) {
+    const int32_t *data = _findMetaData(currency, *ec);
+
+    // If the meta data is invalid, return 0.0.
+    if (data[0] < 0 || data[0] > MAX_POW10) {
+        if (U_SUCCESS(*ec)) {
+            *ec = U_INVALID_FORMAT_ERROR;
+        }
+        return 0.0;
+    }
 
-    // If there is no rounding, or if the meta data is invalid,
-    // return 0.0 to indicate no rounding.  A rounding value
-    // (data[1]) of 0 or 1 indicates no rounding.
-    if (data[1] < 2 || data[0] < 0 || data[0] > MAX_POW10) {
+    // If there is no rounding, return 0.0 to indicate no rounding.  A
+    // rounding value (data[1]) of 0 or 1 indicates no rounding.
+    if (data[1] < 2) {
         return 0.0;
     }
 
@@ -453,12 +739,651 @@ ucurr_getRoundingIncrement(const UChar* currency) {
     return double(data[1]) / POW10[data[0]];
 }
 
-/**
- * Release all static memory held by currency.
- */
-U_CFUNC UBool currency_cleanup(void) {
-    CReg::cleanup();
-    return TRUE;
+U_CDECL_BEGIN
+
+typedef struct UCurrencyContext {
+    uint32_t currType; /* UCurrCurrencyType */
+    uint32_t listIdx;
+} UCurrencyContext;
+
+/*
+Please keep this list in alphabetical order.
+You can look at the CLDR supplemental data or ISO-4217 for the meaning of some
+of these items.
+ISO-4217: http://www.iso.org/iso/en/prods-services/popstds/currencycodeslist.html
+*/
+static const struct CurrencyList {
+    const char *currency;
+    uint32_t currType;
+} gCurrencyList[] = {
+    {"ADP", UCURR_COMMON|UCURR_DEPRECATED},
+    {"AED", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"AFA", UCURR_COMMON|UCURR_DEPRECATED},
+    {"AFN", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"ALK", UCURR_COMMON|UCURR_DEPRECATED},
+    {"ALL", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"AMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"ANG", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"AOA", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"AOK", UCURR_COMMON|UCURR_DEPRECATED},
+    {"AON", UCURR_COMMON|UCURR_DEPRECATED},
+    {"AOR", UCURR_COMMON|UCURR_DEPRECATED},
+    {"ARA", UCURR_COMMON|UCURR_DEPRECATED},
+    {"ARP", UCURR_COMMON|UCURR_DEPRECATED},
+    {"ARS", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"ATS", UCURR_COMMON|UCURR_DEPRECATED},
+    {"AUD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"AWG", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"AZM", UCURR_COMMON|UCURR_DEPRECATED},
+    {"AZN", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"BAD", UCURR_COMMON|UCURR_DEPRECATED},
+    {"BAM", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"BBD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"BDT", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"BEC", UCURR_UNCOMMON|UCURR_DEPRECATED},
+    {"BEF", UCURR_COMMON|UCURR_DEPRECATED},
+    {"BEL", UCURR_UNCOMMON|UCURR_DEPRECATED},
+    {"BGL", UCURR_COMMON|UCURR_DEPRECATED},
+    {"BGM", UCURR_COMMON|UCURR_DEPRECATED},
+    {"BGN", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"BHD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"BIF", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"BMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"BND", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"BOB", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"BOP", UCURR_COMMON|UCURR_DEPRECATED},
+    {"BOV", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+    {"BRB", UCURR_COMMON|UCURR_DEPRECATED},
+    {"BRC", UCURR_COMMON|UCURR_DEPRECATED},
+    {"BRE", UCURR_COMMON|UCURR_DEPRECATED},
+    {"BRL", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"BRN", UCURR_COMMON|UCURR_DEPRECATED},
+    {"BRR", UCURR_COMMON|UCURR_DEPRECATED},
+    {"BSD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"BTN", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"BUK", UCURR_COMMON|UCURR_DEPRECATED},
+    {"BWP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"BYB", UCURR_COMMON|UCURR_DEPRECATED},
+    {"BYR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"BZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"CAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"CDF", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"CHE", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+    {"CHF", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"CHW", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+    {"CLF", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+    {"CLP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"CNX", UCURR_UNCOMMON|UCURR_DEPRECATED},
+    {"CNY", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"COP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"COU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+    {"CRC", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"CSD", UCURR_COMMON|UCURR_DEPRECATED},
+    {"CSK", UCURR_COMMON|UCURR_DEPRECATED},
+    {"CUP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"CVE", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"CYP", UCURR_COMMON|UCURR_DEPRECATED},
+    {"CZK", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"DDM", UCURR_COMMON|UCURR_DEPRECATED},
+    {"DEM", UCURR_COMMON|UCURR_DEPRECATED},
+    {"DJF", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"DKK", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"DOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"DZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"ECS", UCURR_COMMON|UCURR_DEPRECATED},
+    {"ECV", UCURR_UNCOMMON|UCURR_DEPRECATED},
+    {"EEK", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"EGP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"EQE", UCURR_COMMON|UCURR_DEPRECATED},
+    {"ERN", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"ESA", UCURR_UNCOMMON|UCURR_DEPRECATED},
+    {"ESB", UCURR_UNCOMMON|UCURR_DEPRECATED},
+    {"ESP", UCURR_COMMON|UCURR_DEPRECATED},
+    {"ETB", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"EUR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"FIM", UCURR_COMMON|UCURR_DEPRECATED},
+    {"FJD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"FKP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"FRF", UCURR_COMMON|UCURR_DEPRECATED},
+    {"GBP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"GEK", UCURR_COMMON|UCURR_DEPRECATED},
+    {"GEL", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"GHC", UCURR_COMMON|UCURR_DEPRECATED},
+    {"GHS", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"GIP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"GMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"GNF", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"GNS", UCURR_COMMON|UCURR_DEPRECATED},
+    {"GQE", UCURR_COMMON|UCURR_DEPRECATED},
+    {"GRD", UCURR_COMMON|UCURR_DEPRECATED},
+    {"GTQ", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"GWE", UCURR_COMMON|UCURR_DEPRECATED},
+    {"GWP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"GYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"HKD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"HNL", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"HRD", UCURR_COMMON|UCURR_DEPRECATED},
+    {"HRK", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"HTG", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"HUF", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"IDR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"IEP", UCURR_COMMON|UCURR_DEPRECATED},
+    {"ILP", UCURR_COMMON|UCURR_DEPRECATED},
+    {"ILS", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"INR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"IQD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"IRR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"ISK", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"ITL", UCURR_COMMON|UCURR_DEPRECATED},
+    {"JMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"JOD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"JPY", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"KES", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"KGS", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"KHR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"KMF", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"KPW", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"KRW", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"KWD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"KYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"KZT", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"LAK", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"LBP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"LKR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"LRD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"LSL", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"LSM", UCURR_COMMON|UCURR_DEPRECATED},
+    {"LTL", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"LTT", UCURR_COMMON|UCURR_DEPRECATED},
+    {"LUC", UCURR_UNCOMMON|UCURR_DEPRECATED},
+    {"LUF", UCURR_COMMON|UCURR_DEPRECATED},
+    {"LUL", UCURR_UNCOMMON|UCURR_DEPRECATED},
+    {"LVL", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"LVR", UCURR_COMMON|UCURR_DEPRECATED},
+    {"LYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"MAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"MAF", UCURR_COMMON|UCURR_DEPRECATED},
+    {"MDL", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"MGA", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"MGF", UCURR_COMMON|UCURR_DEPRECATED},
+    {"MKD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"MLF", UCURR_COMMON|UCURR_DEPRECATED},
+    {"MMK", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"MNT", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"MOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"MRO", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"MTL", UCURR_COMMON|UCURR_DEPRECATED},
+    {"MTP", UCURR_COMMON|UCURR_DEPRECATED},
+    {"MUR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"MVR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"MWK", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"MXN", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"MXP", UCURR_COMMON|UCURR_DEPRECATED},
+    {"MXV", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+    {"MYR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"MZE", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"MZM", UCURR_COMMON|UCURR_DEPRECATED},
+    {"MZN", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"NAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"NGN", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"NIC", UCURR_COMMON|UCURR_DEPRECATED},
+    {"NIO", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"NLG", UCURR_COMMON|UCURR_DEPRECATED},
+    {"NOK", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"NPR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"NZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"OMR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"PAB", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"PEI", UCURR_COMMON|UCURR_DEPRECATED},
+    {"PEN", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"PES", UCURR_COMMON|UCURR_DEPRECATED},
+    {"PGK", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"PHP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"PKR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"PLN", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"PLZ", UCURR_COMMON|UCURR_DEPRECATED},
+    {"PTE", UCURR_COMMON|UCURR_DEPRECATED},
+    {"PYG", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"QAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"RHD", UCURR_COMMON|UCURR_DEPRECATED},
+    {"ROL", UCURR_COMMON|UCURR_DEPRECATED},
+    {"RON", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"RSD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"RUB", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"RUR", UCURR_COMMON|UCURR_DEPRECATED},
+    {"RWF", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"SAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"SBD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"SCR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"SDD", UCURR_COMMON|UCURR_DEPRECATED},
+    {"SDG", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"SDP", UCURR_COMMON|UCURR_DEPRECATED},
+    {"SEK", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"SGD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"SHP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"SIT", UCURR_COMMON|UCURR_DEPRECATED},
+    {"SKK", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"SLL", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"SOS", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"SRD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"SRG", UCURR_COMMON|UCURR_DEPRECATED},
+    {"STD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"SUR", UCURR_COMMON|UCURR_DEPRECATED},
+    {"SVC", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"SYP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"SZL", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"THB", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"TJR", UCURR_COMMON|UCURR_DEPRECATED},
+    {"TJS", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"TMM", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"TND", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"TOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"TPE", UCURR_COMMON|UCURR_DEPRECATED},
+    {"TRL", UCURR_COMMON|UCURR_DEPRECATED},
+    {"TRY", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"TTD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"TWD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"TZS", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"UAH", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"UAK", UCURR_COMMON|UCURR_DEPRECATED},
+    {"UGS", UCURR_COMMON|UCURR_DEPRECATED},
+    {"UGX", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"USD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"USN", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+    {"USS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+    {"UYP", UCURR_COMMON|UCURR_DEPRECATED},
+    {"UYI", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+    {"UYU", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"UZS", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"VEB", UCURR_COMMON|UCURR_DEPRECATED},
+    {"VEF", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"VND", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"VUV", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"WST", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"XAF", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"XAG", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+    {"XAU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+    {"XBA", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+    {"XBB", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+    {"XBC", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+    {"XBD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+    {"XCD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"XDR", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+    {"XEU", UCURR_UNCOMMON|UCURR_DEPRECATED},
+    {"XFO", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+    {"XFU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+    {"XOF", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"XPD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+    {"XPF", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"XPT", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+    {"XRE", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+    {"XTS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+    {"XXX", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+    {"YDD", UCURR_COMMON|UCURR_DEPRECATED},
+    {"YER", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"YUD", UCURR_COMMON|UCURR_DEPRECATED},
+    {"YUM", UCURR_COMMON|UCURR_DEPRECATED},
+    {"YUN", UCURR_COMMON|UCURR_DEPRECATED},
+    {"ZAL", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+    {"ZAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"ZMK", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    {"ZRN", UCURR_COMMON|UCURR_DEPRECATED},
+    {"ZRZ", UCURR_COMMON|UCURR_DEPRECATED},
+    {"ZWD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+    { NULL, 0 } // Leave here to denote the end of the list.
+};
+
+#define UCURR_MATCHES_BITMASK(variable, typeToMatch) \
+    ((typeToMatch) == UCURR_ALL || ((variable) & (typeToMatch)) == (typeToMatch))
+
+static int32_t U_CALLCONV
+ucurr_countCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) {
+    UCurrencyContext *myContext = (UCurrencyContext *)(enumerator->context);
+    uint32_t currType = myContext->currType;
+    int32_t count = 0;
+
+    /* Count the number of items matching the type we are looking for. */
+    for (int32_t idx = 0; gCurrencyList[idx].currency != NULL; idx++) {
+        if (UCURR_MATCHES_BITMASK(gCurrencyList[idx].currType, currType)) {
+            count++;
+        }
+    }
+    return count;
+}
+
+static const char* U_CALLCONV
+ucurr_nextCurrencyList(UEnumeration *enumerator,
+                        int32_t* resultLength,
+                        UErrorCode * /*pErrorCode*/)
+{
+    UCurrencyContext *myContext = (UCurrencyContext *)(enumerator->context);
+
+    /* Find the next in the list that matches the type we are looking for. */
+    while (myContext->listIdx < (sizeof(gCurrencyList)/sizeof(gCurrencyList[0]))-1) {
+        const struct CurrencyList *currItem = &gCurrencyList[myContext->listIdx++];
+        if (UCURR_MATCHES_BITMASK(currItem->currType, myContext->currType))
+        {
+            if (resultLength) {
+                *resultLength = 3; /* Currency codes are only 3 chars long */
+            }
+            return currItem->currency;
+        }
+    }
+    /* We enumerated too far. */
+    if (resultLength) {
+        *resultLength = 0;
+    }
+    return NULL;
+}
+
+static void U_CALLCONV
+ucurr_resetCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) {
+    ((UCurrencyContext *)(enumerator->context))->listIdx = 0;
+}
+
+static void U_CALLCONV
+ucurr_closeCurrencyList(UEnumeration *enumerator) {
+    uprv_free(enumerator->context);
+    uprv_free(enumerator);
+}
+
+static const UEnumeration gEnumCurrencyList = {
+    NULL,
+    NULL,
+    ucurr_closeCurrencyList,
+    ucurr_countCurrencyList,
+    uenum_unextDefault,
+    ucurr_nextCurrencyList,
+    ucurr_resetCurrencyList
+};
+U_CDECL_END
+
+U_CAPI UEnumeration * U_EXPORT2
+ucurr_openISOCurrencies(uint32_t currType, UErrorCode *pErrorCode) {
+    UEnumeration *myEnum = NULL;
+    UCurrencyContext *myContext;
+
+    myEnum = (UEnumeration*)uprv_malloc(sizeof(UEnumeration));
+    if (myEnum == NULL) {
+        *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+    uprv_memcpy(myEnum, &gEnumCurrencyList, sizeof(UEnumeration));
+    myContext = (UCurrencyContext*)uprv_malloc(sizeof(UCurrencyContext));
+    if (myContext == NULL) {
+        *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
+        uprv_free(myEnum);
+        return NULL;
+    }
+    myContext->currType = currType;
+    myContext->listIdx = 0;
+    myEnum->context = myContext;
+    return myEnum;
+}
+
+U_CAPI int32_t U_EXPORT2
+ucurr_countCurrencies(const char* locale, 
+                 UDate date, 
+                 UErrorCode* ec)
+{
+       int32_t currCount = 0;
+    int32_t resLen = 0;
+    const UChar* s = NULL;
+
+    if (ec != NULL && U_SUCCESS(*ec)) 
+       {
+               // local variables
+        UErrorCode localStatus = U_ZERO_ERROR;
+        char id[ULOC_FULLNAME_CAPACITY];
+        resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus);
+
+               // get country or country_variant in `id'
+               uint32_t variantType = idForLocale(locale, id, sizeof(id), ec);
+               if (U_FAILURE(*ec)) 
+               {
+                       return 0;
+               }
+
+               // Remove variants, which is only needed for registration.
+               char *idDelim = strchr(id, VAR_DELIM);
+               if (idDelim) 
+               {
+                       idDelim[0] = 0;
+               }
+                       
+               // Look up the CurrencyMap element in the root bundle.
+               UResourceBundle *rb = ures_openDirect(NULL, CURRENCY_DATA, &localStatus);
+               UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
+
+               // Using the id derived from the local, get the currency data
+               UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
+
+               // process each currency to see which one is valid for the given date
+               if (U_SUCCESS(localStatus))
+               {
+                       for (int32_t i=0; i<ures_getSize(countryArray); i++)
+                       {
+                               // get the currency resource
+                               UResourceBundle *currencyRes = ures_getByIndex(countryArray, i, NULL, &localStatus);
+                               s = ures_getStringByKey(currencyRes, "id", &resLen, &localStatus);
+
+                               // get the from date
+                               int32_t fromLength = 0;
+                               UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus);
+                               const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus);
+
+                               int64_t currDate64 = (int64_t)fromArray[0] << 32;                       
+                               currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
+                               UDate fromDate = (UDate)currDate64;
+                                       
+                               if (ures_getSize(currencyRes) > 2)
+                               {
+                                       int32_t toLength = 0;
+                                       UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus);
+                                       const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus);
+                                                       
+                                       currDate64 = (int64_t)toArray[0] << 32;                 
+                                       currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
+                                       UDate toDate = (UDate)currDate64;                       
+
+                                       if ((fromDate <= date) && (date < toDate))
+                                       {
+                                               currCount++;
+                                       }
+
+                                       ures_close(toRes);
+                               }
+                               else
+                               {
+                                       if (fromDate <= date)
+                                       {
+                                               currCount++;
+                                       }
+                               }
+
+                               // close open resources
+                               ures_close(currencyRes);
+                               ures_close(fromRes);
+
+                       } // end For loop
+               } // end if (U_SUCCESS(localStatus))
+
+               ures_close(countryArray);
+
+               // Check for errors
+        if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR) 
+               {
+                       // There is nothing to fallback to. 
+                       // Report the failure/warning if possible.
+                       *ec = localStatus;
+               }
+
+               if (U_SUCCESS(*ec)) 
+               {
+                       // no errors
+                       return currCount;
+               }
+
+    }
+
+       // If we got here, either error code is invalid or
+       // some argument passed is no good.
+    return 0;
+}
+
+U_CAPI int32_t U_EXPORT2 
+ucurr_forLocaleAndDate(const char* locale, 
+                UDate date, 
+                int32_t index,
+                UChar* buff, 
+                int32_t buffCapacity, 
+                UErrorCode* ec)
+{
+    int32_t resLen = 0;
+       int32_t currIndex = 0;
+    const UChar* s = NULL;
+
+    if (ec != NULL && U_SUCCESS(*ec)) 
+       {
+               // check the arguments passed
+        if ((buff && buffCapacity) || !buffCapacity ) 
+               {
+                       // local variables
+            UErrorCode localStatus = U_ZERO_ERROR;
+            char id[ULOC_FULLNAME_CAPACITY];
+            resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus);
+
+                       // get country or country_variant in `id'
+                       uint32_t variantType = idForLocale(locale, id, sizeof(id), ec);
+                       if (U_FAILURE(*ec)) 
+                       {
+                               return 0;
+                       }
+
+                       // Remove variants, which is only needed for registration.
+                       char *idDelim = strchr(id, VAR_DELIM);
+                       if (idDelim) 
+                       {
+                               idDelim[0] = 0;
+                       }
+                       
+                       // Look up the CurrencyMap element in the root bundle.
+                       UResourceBundle *rb = ures_openDirect(NULL, CURRENCY_DATA, &localStatus);
+                       UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
+
+                       // Using the id derived from the local, get the currency data
+                       UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
+
+                       // process each currency to see which one is valid for the given date
+                       bool matchFound = false;
+                       if (U_SUCCESS(localStatus))
+                       {
+                if ((index <= 0) || (index > ures_getSize(countryArray)))
+                               {
+                    // requested index is out of bounds
+                    ures_close(countryArray);
+                                       return 0;
+                               }
+
+                               for (int32_t i=0; i<ures_getSize(countryArray); i++)
+                               {
+                                       // get the currency resource
+                                       UResourceBundle *currencyRes = ures_getByIndex(countryArray, i, NULL, &localStatus);
+                                       s = ures_getStringByKey(currencyRes, "id", &resLen, &localStatus);
+
+                                       // get the from date
+                                       int32_t fromLength = 0;
+                                       UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus);
+                                       const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus);
+
+                                       int64_t currDate64 = (int64_t)fromArray[0] << 32;                       
+                                       currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
+                                       UDate fromDate = (UDate)currDate64;
+                                       
+                                       if (ures_getSize(currencyRes) > 2)
+                                       {
+                                               int32_t toLength = 0;
+                                               UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus);
+                                               const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus);
+                                                       
+                                               currDate64 = (int64_t)toArray[0] << 32;                 
+                                               currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
+                                               UDate toDate = (UDate)currDate64;                       
+
+                                               if ((fromDate <= date) && (date < toDate))
+                                               {
+                                                       currIndex++;
+                                                       if (currIndex == index)
+                                                       {
+                                                           matchFound = true;
+                                                       }
+                                               }
+
+                                               ures_close(toRes);
+                                       }
+                                       else
+                                       {
+                                               if (fromDate <= date)
+                                               {
+                                                       currIndex++;
+                                                       if (currIndex == index)
+                                                       {
+                                                           matchFound = true;
+                                                       }
+                                               }
+                                       }
+
+                                       // close open resources
+                                       ures_close(currencyRes);
+                                       ures_close(fromRes);
+                                       
+                                       // check for loop exit
+                                       if (matchFound)
+                                       {
+                                               break;
+                                       }
+
+                               } // end For loop
+                       }
+
+                       ures_close(countryArray);
+
+                       // Check for errors
+            if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR) 
+                       {
+                               // There is nothing to fallback to. 
+                               // Report the failure/warning if possible.
+                               *ec = localStatus;
+                       }
+
+                       if (U_SUCCESS(*ec)) 
+                       {
+                               // no errors
+                               if((buffCapacity > resLen) && matchFound)
+                               {
+                                       // write out the currency value
+                                       u_strcpy(buff, s);
+                               }
+                               else
+                               {
+                                       return 0;
+                               }
+                       }
+
+                       // return null terminated currency string
+            return u_terminateUChars(buff, buffCapacity, resLen, ec);
+               }
+        else 
+               {
+                       // illegal argument encountered
+            *ec = U_ILLEGAL_ARGUMENT_ERROR;
+        }
+
+    }
+
+       // If we got here, either error code is invalid or
+       // some argument passed is no good.
+    return resLen;
 }
 
 #endif /* #if !UCONFIG_NO_FORMATTING */