]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/dcfmtsym.cpp
ICU-461.12.tar.gz
[apple/icu.git] / icuSources / i18n / dcfmtsym.cpp
index c0eccac381d2d8bc25754d8febbf773ce8e4912a..eaab453d7374a217913203fbb136587968bc33e3 100644 (file)
@@ -1,6 +1,6 @@
 /*
 *******************************************************************************
-* Copyright (C) 1997-2008, International Business Machines Corporation and    *
+* Copyright (C) 1997-2010, International Business Machines Corporation and    *
 * others. All Rights Reserved.                                                *
 *******************************************************************************
 *
@@ -16,7 +16,7 @@
 *   07/20/98    stephen     Slightly modified initialization of monetarySeparator
 ********************************************************************************
 */
+
 #include "unicode/utypes.h"
 
 #if !UCONFIG_NO_FORMATTING
 #include "unicode/decimfmt.h"
 #include "unicode/ucurr.h"
 #include "unicode/choicfmt.h"
+#include "unicode/unistr.h"
+#include "unicode/numsys.h"
 #include "ucurrimp.h"
 #include "cstring.h"
 #include "locbased.h"
 #include "uresimp.h"
+#include "ureslocs.h"
+
 // *****************************************************************************
 // class DecimalFormatSymbols
 // *****************************************************************************
+
 U_NAMESPACE_BEGIN
 
 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DecimalFormatSymbols)
 
 static const char gNumberElements[] = "NumberElements";
+static const char gCurrencySpacingTag[] = "currencySpacing";
+static const char gBeforeCurrencyTag[] = "beforeCurrency";
+static const char gAfterCurrencyTag[] = "afterCurrency";
+static const char gCurrencyMatchTag[] = "currencyMatch";
+static const char gCurrencySudMatchTag[] = "surroundingMatch";
+static const char gCurrencyInsertBtnTag[] = "insertBetween";
+
 
 static const UChar INTL_CURRENCY_SYMBOL_STR[] = {0xa4, 0xa4, 0};
 
 // -------------------------------------
 // Initializes this with the decimal format symbols in the default locale.
+
 DecimalFormatSymbols::DecimalFormatSymbols(UErrorCode& status)
     : UObject(),
     locale()
 {
     initialize(locale, status, TRUE);
 }
+
 // -------------------------------------
 // Initializes this with the decimal format symbols in the desired locale.
+
 DecimalFormatSymbols::DecimalFormatSymbols(const Locale& loc, UErrorCode& status)
     : UObject(),
     locale(loc)
 {
     initialize(locale, status);
 }
+
 // -------------------------------------
 
 DecimalFormatSymbols::~DecimalFormatSymbols()
@@ -88,6 +99,10 @@ DecimalFormatSymbols::operator=(const DecimalFormatSymbols& rhs)
             // fastCopyFrom is safe, see docs on fSymbols
             fSymbols[(ENumberFormatSymbol)i].fastCopyFrom(rhs.fSymbols[(ENumberFormatSymbol)i]);
         }
+        for(int32_t i = 0; i < (int32_t)kCurrencySpacingCount; ++i) {
+            currencySpcBeforeSym[i].fastCopyFrom(rhs.currencySpcBeforeSym[i]);
+            currencySpcAfterSym[i].fastCopyFrom(rhs.currencySpcAfterSym[i]);
+        }
         locale = rhs.locale;
         uprv_strcpy(validLocale, rhs.validLocale);
         uprv_strcpy(actualLocale, rhs.actualLocale);
@@ -108,92 +123,198 @@ DecimalFormatSymbols::operator==(const DecimalFormatSymbols& that) const
             return FALSE;
         }
     }
+    for(int32_t i = 0; i < (int32_t)kCurrencySpacingCount; ++i) {
+        if(currencySpcBeforeSym[i] != that.currencySpcBeforeSym[i]) {
+            return FALSE;
+        }
+        if(currencySpcAfterSym[i] != that.currencySpcAfterSym[i]) {
+            return FALSE;
+        }
+    }
     return locale == that.locale &&
         uprv_strcmp(validLocale, that.validLocale) == 0 &&
         uprv_strcmp(actualLocale, that.actualLocale) == 0;
 }
+
 // -------------------------------------
+
 void
-DecimalFormatSymbols::initialize(const Locale& loc, UErrorCode& status,
-                                 UBool useLastResortData)
+DecimalFormatSymbols::initialize(const Locale& loc, UErrorCode& status, UBool useLastResortData)
 {
+    static const char *gNumberElementKeys[kFormatSymbolCount] = {
+        "decimal",
+        "group",
+        "list",
+        "percentSign",
+        NULL, /* Native zero digit is deprecated from CLDR - get it from the numbering system */
+        NULL, /* Pattern digit character is deprecated from CLDR - use # by default always */
+        "minusSign",
+        "plusSign",
+        NULL, /* currency symbol - We don't really try to load this directly from CLDR until we know the currency */
+        NULL, /* intl currency symbol - We don't really try to load this directly from CLDR until we know the currency */
+        "currencyDecimal",
+        "exponential",
+        "perMille",
+        NULL, /* Escape padding character - not in CLDR */
+        "infinity",
+        "nan",
+        NULL, /* Significant digit symbol - not in CLDR */
+        "currencyGroup",
+        NULL, /* one digit - get it from the numbering system */
+        NULL, /* two digit - get it from the numbering system */
+        NULL, /* three digit - get it from the numbering system */
+        NULL, /* four digit - get it from the numbering system */
+        NULL, /* five digit - get it from the numbering system */
+        NULL, /* six digit - get it from the numbering system */
+        NULL, /* seven digit - get it from the numbering system */
+        NULL, /* eight digit - get it from the numbering system */
+        NULL, /* nine digit - get it from the numbering system */
+    };
+
+    static const char *gLatn =  "latn";
+    static const char *gSymbols = "symbols";
+    const char *nsName;
+    const UChar *sym = NULL;
+    int32_t len = 0;
+
     *validLocale = *actualLocale = 0;
     currPattern = NULL;
     if (U_FAILURE(status))
         return;
-    
+
     const char* locStr = loc.getName();
     UResourceBundle *resource = ures_open((char *)0, locStr, &status);
-    UResourceBundle *numberElementsRes = ures_getByKey(resource, gNumberElements, NULL, &status);
-    if (U_FAILURE(status))
-    {
-        // Initializes with last resort data if necessary.
-        if (useLastResortData)
-        {
+    UResourceBundle *numberElementsRes = ures_getByKeyWithFallback(resource, gNumberElements, NULL, &status);
+
+    if (U_FAILURE(status)) {
+        if ( useLastResortData ) {
             status = U_USING_FALLBACK_WARNING;
             initialize();
         }
-    }
-    else {
-        // Gets the number element array.
-        int32_t numberElementsLength = ures_getSize(numberElementsRes);
+        return;
+    } else {
+
+        // First initialize all the symbols to the fallbacks for anything we can't find
+        initialize();
 
-        if (numberElementsLength > (int32_t)kFormatSymbolCount) {
-            /* Warning: Invalid format. Array too large. */
-            numberElementsLength = (int32_t)kFormatSymbolCount;
+        //
+        // Next get the numbering system for this locale and set zero digit
+        // and the digit string based on the numbering system for the locale
+        //
+
+        NumberingSystem* ns = NumberingSystem::createInstance(loc,status);
+        if (U_SUCCESS(status) && ns->getRadix() == 10 && !ns->isAlgorithmic()) {
+            nsName = ns->getName();
+            UnicodeString *DigitString = new UnicodeString(ns->getDescription());
+                setSymbol(kZeroDigitSymbol,DigitString->charAt(0),FALSE);
+                setSymbol(kOneDigitSymbol,DigitString->charAt(1),FALSE);
+                setSymbol(kTwoDigitSymbol,DigitString->charAt(2),FALSE);
+                setSymbol(kThreeDigitSymbol,DigitString->charAt(3),FALSE);
+                setSymbol(kFourDigitSymbol,DigitString->charAt(4),FALSE);
+                setSymbol(kFiveDigitSymbol,DigitString->charAt(5),FALSE);
+                setSymbol(kSixDigitSymbol,DigitString->charAt(6),FALSE);
+                setSymbol(kSevenDigitSymbol,DigitString->charAt(7),FALSE);
+                setSymbol(kEightDigitSymbol,DigitString->charAt(8),FALSE);
+                setSymbol(kNineDigitSymbol,DigitString->charAt(9),FALSE);
+            delete DigitString;
+        } else {
+            nsName = gLatn;
         }
-        // If the array size is too small, something is wrong with the resource
-        // bundle, returns the failure error code.
-        if (numberElementsLength != 12 || U_FAILURE(status)) {
-            status = U_INVALID_FORMAT_ERROR;
+       
+        UBool isLatn = !uprv_strcmp(nsName,gLatn);
+
+        UErrorCode nlStatus = U_ZERO_ERROR;
+        UResourceBundle *nonLatnSymbols = NULL;
+        if ( !isLatn ) {
+            nonLatnSymbols = ures_getByKeyWithFallback(numberElementsRes, nsName, NULL, &nlStatus);
+            nonLatnSymbols = ures_getByKeyWithFallback(nonLatnSymbols, gSymbols, nonLatnSymbols, &nlStatus);
         }
-        else {
-            const UChar *numberElements[kFormatSymbolCount];
-            int32_t numberElementsStrLen[kFormatSymbolCount];
-            int32_t i = 0;
-            for(i = 0; i<numberElementsLength; i++) {
-                numberElements[i] = ures_getStringByIndex(numberElementsRes, i, &numberElementsStrLen[i], &status);
-            }
 
-            if (U_SUCCESS(status)) {
-                initialize(numberElements, numberElementsStrLen, numberElementsLength);
-
-                // Obtain currency data from the currency API.  This is strictly
-                // for backward compatibility; we don't use DecimalFormatSymbols
-                // for currency data anymore.
-                UErrorCode internalStatus = U_ZERO_ERROR; // don't propagate failures out
-                UChar curriso[4];
-                UnicodeString tempStr;
-                ucurr_forLocale(locStr, curriso, 4, &internalStatus);
-
-                // Reuse numberElements[0] as a temporary buffer
-                uprv_getStaticCurrencyName(curriso, locStr, tempStr, internalStatus);
-                if (U_SUCCESS(internalStatus)) {
-                    fSymbols[kIntlCurrencySymbol] = curriso;
-                    fSymbols[kCurrencySymbol] = tempStr;
+        UResourceBundle *latnSymbols = ures_getByKeyWithFallback(numberElementsRes, gLatn, NULL, &status);
+        latnSymbols = ures_getByKeyWithFallback(latnSymbols, gSymbols, latnSymbols, &status);
+
+        UBool kMonetaryDecimalSet = FALSE;
+        UBool kMonetaryGroupingSet = FALSE;
+        for(int32_t i = 0; i<kFormatSymbolCount; i++) {
+            if ( gNumberElementKeys[i] != NULL ) {
+                UErrorCode localStatus = U_ZERO_ERROR;
+                if ( !isLatn ) {
+                    sym = ures_getStringByKeyWithFallback(nonLatnSymbols,gNumberElementKeys[i],&len,&localStatus);
+                    // If we can't find the symbol in the numbering system specific resources,
+                    // use the "latn" numbering system as the fallback.
+                    if ( U_FAILURE(localStatus) ) {
+                        localStatus = U_ZERO_ERROR;
+                        sym = ures_getStringByKeyWithFallback(latnSymbols,gNumberElementKeys[i],&len,&localStatus);
+                    }
+                } else {
+                        sym = ures_getStringByKeyWithFallback(latnSymbols,gNumberElementKeys[i],&len,&localStatus);
+                }
+
+                if ( U_SUCCESS(localStatus) ) {
+                    setSymbol((ENumberFormatSymbol)i,sym);
+                    if ( i == kMonetarySeparatorSymbol ) {
+                        kMonetaryDecimalSet = TRUE;
+                    } else if ( i == kMonetaryGroupingSeparatorSymbol ) {
+                        kMonetaryGroupingSet = TRUE;
+                    }
                 }
-                /* else use the default values. */
             }
+        }
+
+        ures_close(latnSymbols);
+        if ( !isLatn ) {
+            ures_close(nonLatnSymbols);
+        }
+
+        // If monetary decimal or grouping were not explicitly set, then set them to be the
+        // same as their non-monetary counterparts.
+
+        if ( !kMonetaryDecimalSet ) {
+            setSymbol(kMonetarySeparatorSymbol,fSymbols[kDecimalSeparatorSymbol]);
+        }
+        if ( !kMonetaryGroupingSet ) {
+            setSymbol(kMonetaryGroupingSeparatorSymbol,fSymbols[kGroupingSeparatorSymbol]);
+        }
 
-            U_LOCALE_BASED(locBased, *this);
-            locBased.setLocaleIDs(ures_getLocaleByType(numberElementsRes,
-                                       ULOC_VALID_LOCALE, &status),
-                                  ures_getLocaleByType(numberElementsRes,
-                                       ULOC_ACTUAL_LOCALE, &status));
+        if (ns) {
+            delete ns;
         }
+
+        // Obtain currency data from the currency API.  This is strictly
+        // for backward compatibility; we don't use DecimalFormatSymbols
+        // for currency data anymore.
+        UErrorCode internalStatus = U_ZERO_ERROR; // don't propagate failures out
+        UChar curriso[4];
+        UnicodeString tempStr;
+        ucurr_forLocale(locStr, curriso, 4, &internalStatus);
+
+        // Reuse numberElements[0] as a temporary buffer
+        uprv_getStaticCurrencyName(curriso, locStr, tempStr, internalStatus);
+        if (U_SUCCESS(internalStatus)) {
+            fSymbols[kIntlCurrencySymbol] = curriso;
+            fSymbols[kCurrencySymbol] = tempStr;
+        }
+        /* else use the default values. */
+
+        U_LOCALE_BASED(locBased, *this);
+        locBased.setLocaleIDs(ures_getLocaleByType(numberElementsRes,
+                              ULOC_VALID_LOCALE, &status),
+                              ures_getLocaleByType(numberElementsRes,
+                              ULOC_ACTUAL_LOCALE, &status));
+        
         //load the currency data
-        UChar ucc[4]={0}; //Currency Codes are always 3 chars long 
+        UChar ucc[4]={0}; //Currency Codes are always 3 chars long
         int32_t uccLen = 4;
         const char* locName = loc.getName();
         UErrorCode localStatus = U_ZERO_ERROR;
         uccLen = ucurr_forLocale(locName, ucc, uccLen, &localStatus);
+
         if(U_SUCCESS(localStatus) && uccLen > 0) {
             char cc[4]={0};
             u_UCharsToChars(ucc, cc, uccLen);
             /* An explicit currency was requested */
-            UResourceBundle *currency = ures_getByKeyWithFallback(resource, "Currencies", NULL, &localStatus);
+            UResourceBundle *currencyResource = ures_open(U_ICUDATA_CURR, locStr, &localStatus);
+            UResourceBundle *currency = ures_getByKeyWithFallback(currencyResource, "Currencies", NULL, &localStatus);
             currency = ures_getByKeyWithFallback(currency, cc, currency, &localStatus);
             if(U_SUCCESS(localStatus) && ures_getSize(currency)>2) { // the length is 3 if more data is present
                 currency = ures_getByIndex(currency, 2, currency, &localStatus);
@@ -209,54 +330,52 @@ DecimalFormatSymbols::initialize(const Locale& loc, UErrorCode& status,
                 }
             }
             ures_close(currency);
+            ures_close(currencyResource);
             /* else An explicit currency was requested and is unknown or locale data is malformed. */
             /* ucurr_* API will get the correct value later on. */
         }
-        // else ignore the error if no currency
-    }
-    ures_close(resource);
-    ures_close(numberElementsRes);
-}
+            // else ignore the error if no currency
 
-// Initializes the DecimalFormatSymbol instance with the data obtained
-// from ResourceBundle in the desired locale.
+        // Currency Spacing.
+        localStatus = U_ZERO_ERROR;
+        UResourceBundle *currencyResource = ures_open(U_ICUDATA_CURR, locStr, &localStatus);
+        UResourceBundle *currencySpcRes = ures_getByKeyWithFallback(currencyResource,
+                                           gCurrencySpacingTag, NULL, &localStatus);
 
-void
-DecimalFormatSymbols::initialize(const UChar** numberElements, int32_t *numberElementsStrLen, int32_t numberElementsLength)
-{
-    static const int8_t TYPE_MAPPING[][2] = {
-        {kDecimalSeparatorSymbol, 0},
-        {kGroupingSeparatorSymbol, 1},
-        {kPatternSeparatorSymbol, 2},
-        {kPercentSymbol, 3},
-        {kZeroDigitSymbol, 4},
-        {kDigitSymbol, 5},
-        {kMinusSignSymbol, 6},
-        {kExponentialSymbol, 7},
-        {kPerMillSymbol, 8},
-        {kInfinitySymbol, 9},
-        {kNaNSymbol, 10},
-        {kPlusSignSymbol, 11},
-        {kMonetarySeparatorSymbol, 0}
-    };
-    int32_t idx;
-
-    for (idx = 0; idx < (int32_t)(sizeof(TYPE_MAPPING)/sizeof(TYPE_MAPPING[0])); idx++) {
-        if (TYPE_MAPPING[idx][1] < numberElementsLength) {
-            fSymbols[TYPE_MAPPING[idx][0]].setTo(TRUE, numberElements[TYPE_MAPPING[idx][1]], numberElementsStrLen[TYPE_MAPPING[idx][1]]);
+        if (localStatus == U_USING_FALLBACK_WARNING || U_SUCCESS(localStatus)) {
+            const char* keywords[kCurrencySpacingCount] = {
+                gCurrencyMatchTag, gCurrencySudMatchTag, gCurrencyInsertBtnTag
+            };
+            localStatus = U_ZERO_ERROR;
+            UResourceBundle *dataRes = ures_getByKeyWithFallback(currencySpcRes,
+                                       gBeforeCurrencyTag, NULL, &localStatus);
+            if (localStatus == U_USING_FALLBACK_WARNING || U_SUCCESS(localStatus)) {
+                localStatus = U_ZERO_ERROR;
+                for (int32_t i = 0; i < kCurrencySpacingCount; i++) {
+                  currencySpcBeforeSym[i] = ures_getStringByKey(dataRes, keywords[i],
+                                                            NULL, &localStatus);
+                }
+                ures_close(dataRes);
+            }
+            dataRes = ures_getByKeyWithFallback(currencySpcRes,
+                                      gAfterCurrencyTag, NULL, &localStatus);
+            if (localStatus == U_USING_FALLBACK_WARNING || U_SUCCESS(localStatus)) {
+                localStatus = U_ZERO_ERROR;
+                for (int32_t i = 0; i < kCurrencySpacingCount; i++) {
+                  currencySpcAfterSym[i] = ures_getStringByKey(dataRes, keywords[i],
+                                                                NULL, &localStatus);
+                }
+                ures_close(dataRes);
+            }
+            ures_close(currencySpcRes);
+            ures_close(currencyResource);
         }
     }
+    ures_close(resource);
+    ures_close(numberElementsRes);
 
-    // Default values until it's set later on.
-    fSymbols[kCurrencySymbol] = (UChar)0xa4;            // 'OX' currency symbol
-    fSymbols[kIntlCurrencySymbol] = INTL_CURRENCY_SYMBOL_STR;
-    // TODO: read from locale data, if this makes it into CLDR
-    fSymbols[kSignificantDigitSymbol] = (UChar)0x0040;  // '@' significant digit
-    fSymbols[kPadEscapeSymbol] = (UChar)0x002a; // TODO: '*' Hard coded for now; get from resource later
-    fSymbols[kMonetaryGroupingSeparatorSymbol] = fSymbols[kGroupingSeparatorSymbol];
 }
 
-// initialize with default values
 void
 DecimalFormatSymbols::initialize() {
     /*
@@ -269,6 +388,15 @@ DecimalFormatSymbols::initialize() {
     fSymbols[kPatternSeparatorSymbol] = (UChar)0x3b;    // ';' pattern separator
     fSymbols[kPercentSymbol] = (UChar)0x25;             // '%' percent sign
     fSymbols[kZeroDigitSymbol] = (UChar)0x30;           // '0' native 0 digit
+    fSymbols[kOneDigitSymbol] = (UChar)0x31;            // '1' native 1 digit
+    fSymbols[kTwoDigitSymbol] = (UChar)0x32;            // '2' native 2 digit
+    fSymbols[kThreeDigitSymbol] = (UChar)0x33;          // '3' native 3 digit
+    fSymbols[kFourDigitSymbol] = (UChar)0x34;           // '4' native 4 digit
+    fSymbols[kFiveDigitSymbol] = (UChar)0x35;           // '5' native 5 digit
+    fSymbols[kSixDigitSymbol] = (UChar)0x36;            // '6' native 6 digit
+    fSymbols[kSevenDigitSymbol] = (UChar)0x37;          // '7' native 7 digit
+    fSymbols[kEightDigitSymbol] = (UChar)0x38;          // '8' native 8 digit
+    fSymbols[kNineDigitSymbol] = (UChar)0x39;           // '9' native 9 digit
     fSymbols[kDigitSymbol] = (UChar)0x23;               // '#' pattern digit
     fSymbols[kPlusSignSymbol] = (UChar)0x002b;          // '+' plus sign
     fSymbols[kMinusSignSymbol] = (UChar)0x2d;           // '-' minus sign
@@ -281,14 +409,39 @@ DecimalFormatSymbols::initialize() {
     fSymbols[kInfinitySymbol] = (UChar)0x221e;          // 'oo' infinite
     fSymbols[kNaNSymbol] = (UChar)0xfffd;               // SUB NaN
     fSymbols[kSignificantDigitSymbol] = (UChar)0x0040;  // '@' significant digit
+    fSymbols[kMonetaryGroupingSeparatorSymbol].remove(); // 
 }
 
-Locale 
+Locale
 DecimalFormatSymbols::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
     U_LOCALE_BASED(locBased, *this);
     return locBased.getLocale(type, status);
 }
 
+const UnicodeString&
+DecimalFormatSymbols::getPatternForCurrencySpacing(ECurrencySpacing type,
+                                                 UBool beforeCurrency,
+                                                 UErrorCode& status) const {
+    if (U_FAILURE(status)) {
+      return fNoSymbol;  // always empty.
+    }
+    if (beforeCurrency) {
+      return currencySpcBeforeSym[(int32_t)type];
+    } else {
+      return currencySpcAfterSym[(int32_t)type];
+    }
+}
+
+void
+DecimalFormatSymbols::setPatternForCurrencySpacing(ECurrencySpacing type,
+                                                   UBool beforeCurrency,
+                                             const UnicodeString& pattern) {
+  if (beforeCurrency) {
+    currencySpcBeforeSym[(int32_t)type] = pattern;
+  } else {
+    currencySpcAfterSym[(int32_t)type] =  pattern;
+  }
+}
 U_NAMESPACE_END
 
 #endif /* #if !UCONFIG_NO_FORMATTING */