]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/unum.cpp
ICU-62141.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / unum.cpp
index b587cfb9c3900fb7461eb6cfcaf9f35cc07b0907..c2bd548879cecb30844bc7a965d44b3afcf3bc8a 100644 (file)
@@ -1,6 +1,8 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
 /*
 *******************************************************************************
-*   Copyright (C) 1996-2004, International Business Machines
+*   Copyright (C) 1996-2015, International Business Machines
 *   Corporation and others.  All Rights Reserved.
 *******************************************************************************
 * Modification History:
 #include "unicode/numfmt.h"
 #include "unicode/decimfmt.h"
 #include "unicode/rbnf.h"
+#include "unicode/compactdecimalformat.h"
 #include "unicode/ustring.h"
 #include "unicode/fmtable.h"
 #include "unicode/dcfmtsym.h"
 #include "unicode/curramt.h"
+#include "unicode/localpointer.h"
+#include "unicode/udisplaycontext.h"
 #include "uassert.h"
 #include "cpputils.h"
+#include "cstring.h"
 
 
 U_NAMESPACE_USE
@@ -37,74 +43,50 @@ unum_open(  UNumberFormatStyle    style,
             int32_t            patternLength,
             const    char*     locale,
             UParseError*       parseErr,
-            UErrorCode*        status)
-{
-
-    if(U_FAILURE(*status))
-    {
-        return 0;
+            UErrorCode*        status) {
+    if(U_FAILURE(*status)) {
+        return NULL;
     }
 
-    UNumberFormat *retVal = 0;
+    NumberFormat *retVal = NULL;
 
     switch(style) {
     case UNUM_DECIMAL:
-        if(locale == 0)
-            retVal = (UNumberFormat*)NumberFormat::createInstance(*status);
-        else
-            retVal = (UNumberFormat*)NumberFormat::createInstance(Locale(locale),
-            *status);
-        break;
-
     case UNUM_CURRENCY:
-        if(locale == 0)
-            retVal = (UNumberFormat*)NumberFormat::createCurrencyInstance(*status);
-        else
-            retVal = (UNumberFormat*)NumberFormat::createCurrencyInstance(Locale(locale),
-            *status);
-        break;
-
     case UNUM_PERCENT:
-        if(locale == 0)
-            retVal = (UNumberFormat*)NumberFormat::createPercentInstance(*status);
-        else
-            retVal = (UNumberFormat*)NumberFormat::createPercentInstance(Locale(locale),
-            *status);
-        break;
-
     case UNUM_SCIENTIFIC:
-        if(locale == 0)
-            retVal = (UNumberFormat*)NumberFormat::createScientificInstance(*status);
-        else
-            retVal = (UNumberFormat*)NumberFormat::createScientificInstance(Locale(locale),
-            *status);
+    case UNUM_CURRENCY_ISO:
+    case UNUM_CURRENCY_PLURAL:
+    case UNUM_CURRENCY_ACCOUNTING:
+    case UNUM_CASH_CURRENCY:
+    case UNUM_CURRENCY_STANDARD:
+        retVal = NumberFormat::createInstance(Locale(locale), style, *status);
         break;
 
     case UNUM_PATTERN_DECIMAL: {
         UParseError tErr;
         /* UnicodeString can handle the case when patternLength = -1. */
         const UnicodeString pat(pattern, patternLength);
-        DecimalFormatSymbols *syms = 0;
 
         if(parseErr==NULL){
             parseErr = &tErr;
         }
 
-        if(locale == 0)
-            syms = new DecimalFormatSymbols(*status);
-        else
-            syms = new DecimalFormatSymbols(Locale(locale), *status);
-
-        if(syms == 0) {
+        DecimalFormatSymbols *syms = new DecimalFormatSymbols(Locale(locale), *status);
+        if(syms == NULL) {
             *status = U_MEMORY_ALLOCATION_ERROR;
-            return 0;
+            return NULL;
+        }
+        if (U_FAILURE(*status)) {
+            delete syms;
+            return NULL;
         }
 
-        retVal = (UNumberFormat*)new DecimalFormat(pat, syms, *parseErr, *status);
-        if(retVal == 0) {
+        retVal = new DecimalFormat(pat, syms, *parseErr, *status);
+        if(retVal == NULL) {
             delete syms;
         }
-                               } break;
+    } break;
 
 #if U_HAVE_RBNF
     case UNUM_PATTERN_RULEBASED: {
@@ -116,32 +98,44 @@ unum_open(  UNumberFormatStyle    style,
             parseErr = &tErr;
         }
         
-        retVal = (UNumberFormat*)new RuleBasedNumberFormat(pat, Locale(locale), *parseErr, *status);
+        retVal = new RuleBasedNumberFormat(pat, Locale(locale), *parseErr, *status);
     } break;
 
     case UNUM_SPELLOUT:
-        retVal = (UNumberFormat*)new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale(locale), *status);
+        retVal = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale(locale), *status);
         break;
 
     case UNUM_ORDINAL:
-        retVal = (UNumberFormat*)new RuleBasedNumberFormat(URBNF_ORDINAL, Locale(locale), *status);
+        retVal = new RuleBasedNumberFormat(URBNF_ORDINAL, Locale(locale), *status);
         break;
 
     case UNUM_DURATION:
-        retVal = (UNumberFormat*)new RuleBasedNumberFormat(URBNF_DURATION, Locale(locale), *status);
+        retVal = new RuleBasedNumberFormat(URBNF_DURATION, Locale(locale), *status);
+        break;
+
+    case UNUM_NUMBERING_SYSTEM:
+        retVal = new RuleBasedNumberFormat(URBNF_NUMBERING_SYSTEM, Locale(locale), *status);
         break;
 #endif
 
+    case UNUM_DECIMAL_COMPACT_SHORT:
+        retVal = CompactDecimalFormat::createInstance(Locale(locale), UNUM_SHORT, *status);
+        break;
+
+    case UNUM_DECIMAL_COMPACT_LONG:
+        retVal = CompactDecimalFormat::createInstance(Locale(locale), UNUM_LONG, *status);
+        break;
+
     default:
         *status = U_UNSUPPORTED_ERROR;
-        return 0;
+        return NULL;
     }
 
-    if(retVal == 0 && U_SUCCESS(*status)) {
+    if(retVal == NULL && U_SUCCESS(*status)) {
         *status = U_MEMORY_ALLOCATION_ERROR;
     }
 
-    return retVal;
+    return reinterpret_cast<UNumberFormat *>(retVal);
 }
 
 U_CAPI void U_EXPORT2
@@ -158,11 +152,14 @@ unum_clone(const UNumberFormat *fmt,
         return 0;
     
     Format *res = 0;
-    if (((const NumberFormat*)fmt)->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
-        res = ((const DecimalFormat*)fmt)->clone();
+    const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
+    const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
+    if (df != NULL) {
+        res = df->clone();
     } else {
-        U_ASSERT(((const NumberFormat*)fmt)->getDynamicClassID() == RuleBasedNumberFormat::getStaticClassID());
-        res = ((const RuleBasedNumberFormat*)fmt)->clone();
+        const RuleBasedNumberFormat* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf);
+        U_ASSERT(rbnf != NULL);
+        res = rbnf->clone();
     }
 
     if(res == 0) {
@@ -207,8 +204,13 @@ unum_formatInt64(const UNumberFormat* fmt,
     if(pos != 0)
         fp.setField(pos->field);
     
-    ((const NumberFormat*)fmt)->format(number, res, fp);
-    
+    const CompactDecimalFormat* cdf = dynamic_cast<const CompactDecimalFormat*>((const NumberFormat*)fmt);
+    if (cdf != NULL) {
+        cdf->format(number, res, fp); // CompactDecimalFormat does not override the version with UErrorCode& !!
+    } else {
+        ((const NumberFormat*)fmt)->format(number, res, fp, *status);
+    }
+
     if(pos != 0) {
         pos->beginIndex = fp.getBeginIndex();
         pos->endIndex = fp.getEndIndex();
@@ -240,7 +242,12 @@ unum_formatDouble(    const    UNumberFormat*  fmt,
   if(pos != 0)
     fp.setField(pos->field);
   
-  ((const NumberFormat*)fmt)->format(number, res, fp);
+  const CompactDecimalFormat* cdf = dynamic_cast<const CompactDecimalFormat*>((const NumberFormat*)fmt);
+  if (cdf != NULL) {
+      cdf->format(number, res, fp); // CompactDecimalFormat does not override the version with UErrorCode& !!
+  } else {
+      ((const NumberFormat*)fmt)->format(number, res, fp, *status);
+  }
   
   if(pos != 0) {
     pos->beginIndex = fp.getBeginIndex();
@@ -250,7 +257,79 @@ unum_formatDouble(    const    UNumberFormat*  fmt,
   return res.extract(result, resultLength, *status);
 }
 
-U_DRAFT int32_t U_EXPORT2 
+U_CAPI int32_t U_EXPORT2
+unum_formatDoubleForFields(const UNumberFormat* format,
+                           double number,
+                           UChar* result,
+                           int32_t resultLength,
+                           UFieldPositionIterator* fpositer,
+                           UErrorCode* status)
+{
+    if (U_FAILURE(*status))
+        return -1;
+
+    if (result == NULL ? resultLength != 0 : resultLength < 0) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return -1;
+    }
+
+    UnicodeString res;
+    if (result != NULL) {
+        // NULL destination for pure preflighting: empty dummy string
+        // otherwise, alias the destination buffer
+        res.setTo(result, 0, resultLength);
+    }
+
+    ((const NumberFormat*)format)->format(number, res, (FieldPositionIterator*)fpositer, *status);
+
+    return res.extract(result, resultLength, *status);
+}
+
+U_CAPI int32_t U_EXPORT2 
+unum_formatDecimal(const    UNumberFormat*  fmt,
+            const char *    number,
+            int32_t         length,
+            UChar*          result,
+            int32_t         resultLength,
+            UFieldPosition  *pos, /* 0 if ignore */
+            UErrorCode*     status) {
+
+    if(U_FAILURE(*status)) {
+        return -1;
+    }
+    if ((result == NULL && resultLength != 0) || resultLength < 0) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return -1;
+    }
+
+    FieldPosition fp;
+    if(pos != 0) {
+        fp.setField(pos->field);
+    }
+
+    if (length < 0) {
+        length = static_cast<int32_t>(uprv_strlen(number));
+    }
+    StringPiece numSP(number, length);
+    Formattable numFmtbl(numSP, *status);
+
+    UnicodeString resultStr;
+    if (resultLength > 0) {
+        // Alias the destination buffer.
+        resultStr.setTo(result, 0, resultLength);
+    }
+    ((const NumberFormat*)fmt)->format(numFmtbl, resultStr, fp, *status);
+    if(pos != 0) {
+        pos->beginIndex = fp.getBeginIndex();
+        pos->endIndex = fp.getEndIndex();
+    }
+    return resultStr.extract(result, resultLength, *status);
+}
+
+
+
+
+U_CAPI int32_t U_EXPORT2 
 unum_formatDoubleCurrency(const UNumberFormat* fmt,
                           double number,
                           UChar* currency,
@@ -271,8 +350,13 @@ unum_formatDoubleCurrency(const UNumberFormat* fmt,
     if (pos != 0) {
         fp.setField(pos->field);
     }
-
-    Formattable n(new CurrencyAmount(number, currency, *status));
+    CurrencyAmount *tempCurrAmnt = new CurrencyAmount(number, currency, *status);
+    // Check for null pointer.
+    if (tempCurrAmnt == NULL) {
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        return -1;
+    }
+    Formattable n(tempCurrAmnt);
     ((const NumberFormat*)fmt)->format(n, res, fp, *status);
     
     if (pos != 0) {
@@ -289,32 +373,26 @@ parseRes(Formattable& res,
          const   UChar*          text,
          int32_t         textLength,
          int32_t         *parsePos /* 0 = start */,
-         UBool parseCurrency,
          UErrorCode      *status)
 {
     if(U_FAILURE(*status))
         return;
     
-    int32_t len = (textLength == -1 ? u_strlen(text) : textLength);
-    const UnicodeString src((UChar*)text, len, len);
+    const UnicodeString src((UBool)(textLength == -1), text, textLength);
     ParsePosition pp;
     
     if(parsePos != 0)
         pp.setIndex(*parsePos);
     
-    if (parseCurrency) {
-        ((const NumberFormat*)fmt)->parseCurrency(src, res, pp);
-    } else {
-        ((const NumberFormat*)fmt)->parse(src, res, pp);
-    }
+    ((const NumberFormat*)fmt)->parse(src, res, pp);
     
-    if(parsePos != 0) {
-        if(pp.getErrorIndex() == -1)
-            *parsePos = pp.getIndex();
-        else {
+    if(pp.getErrorIndex() != -1) {
+        *status = U_PARSE_ERROR;
+        if(parsePos != 0) {
             *parsePos = pp.getErrorIndex();
-            *status = U_PARSE_ERROR;
         }
+    } else if(parsePos != 0) {
+        *parsePos = pp.getIndex();
     }
 }
 
@@ -326,7 +404,7 @@ unum_parse(    const   UNumberFormat*  fmt,
         UErrorCode      *status)
 {
     Formattable res;
-    parseRes(res, fmt, text, textLength, parsePos, FALSE, status);
+    parseRes(res, fmt, text, textLength, parsePos, status);
     return res.getLong(*status);
 }
 
@@ -338,7 +416,7 @@ unum_parseInt64(    const   UNumberFormat*  fmt,
         UErrorCode      *status)
 {
     Formattable res;
-    parseRes(res, fmt, text, textLength, parsePos, FALSE, status);
+    parseRes(res, fmt, text, textLength, parsePos, status);
     return res.getInt64(*status);
 }
 
@@ -350,26 +428,77 @@ unum_parseDouble(    const   UNumberFormat*  fmt,
             UErrorCode      *status)
 {
     Formattable res;
-    parseRes(res, fmt, text, textLength, parsePos, FALSE, status);
+    parseRes(res, fmt, text, textLength, parsePos, status);
     return res.getDouble(*status);
 }
 
-U_DRAFT double U_EXPORT2
+U_CAPI int32_t U_EXPORT2
+unum_parseDecimal(const UNumberFormat*  fmt,
+            const UChar*    text,
+            int32_t         textLength,
+            int32_t         *parsePos /* 0 = start */,
+            char            *outBuf,
+            int32_t         outBufLength,
+            UErrorCode      *status)
+{
+    if (U_FAILURE(*status)) {
+        return -1;
+    }
+    if ((outBuf == NULL && outBufLength != 0) || outBufLength < 0) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return -1;
+    }
+    Formattable res;
+    parseRes(res, fmt, text, textLength, parsePos, status);
+    StringPiece sp = res.getDecimalNumber(*status);
+    if (U_FAILURE(*status)) {
+       return -1;
+    } else if (sp.size() > outBufLength) {
+        *status = U_BUFFER_OVERFLOW_ERROR;
+    } else if (sp.size() == outBufLength) {
+        uprv_strncpy(outBuf, sp.data(), sp.size());
+        *status = U_STRING_NOT_TERMINATED_WARNING;
+    } else {
+        U_ASSERT(outBufLength > 0);
+        uprv_strcpy(outBuf, sp.data());
+    }
+    return sp.size();
+}
+
+U_CAPI double U_EXPORT2
 unum_parseDoubleCurrency(const UNumberFormat* fmt,
                          const UChar* text,
                          int32_t textLength,
                          int32_t* parsePos, /* 0 = start */
                          UChar* currency,
                          UErrorCode* status) {
-    Formattable res;
-    parseRes(res, fmt, text, textLength, parsePos, TRUE, status);
+    double doubleVal = 0.0;
     currency[0] = 0;
-    if (res.getType() == Formattable::kObject &&
-        res.getObject()->getDynamicClassID() == CurrencyAmount::getStaticClassID()) {
-        const CurrencyAmount* c = (const CurrencyAmount*) res.getObject();
-        u_strcpy(currency, c->getISOCurrency());
+    if (U_FAILURE(*status)) {
+        return doubleVal;
     }
-    return res.getDouble(*status);
+    const UnicodeString src((UBool)(textLength == -1), text, textLength);
+    ParsePosition pp;
+    if (parsePos != NULL) {
+        pp.setIndex(*parsePos);
+    }
+    *status = U_PARSE_ERROR; // assume failure, reset if succeed
+    LocalPointer<CurrencyAmount> currAmt(((const NumberFormat*)fmt)->parseCurrency(src, pp));
+    if (pp.getErrorIndex() != -1) {
+        if (parsePos != NULL) {
+            *parsePos = pp.getErrorIndex();
+        }
+    } else {
+        if (parsePos != NULL) {
+            *parsePos = pp.getIndex();
+        }
+        if (pp.getIndex() > 0) {
+            *status = U_ZERO_ERROR;
+            u_strcpy(currency, currAmt->getISOCurrency());
+            doubleVal = currAmt->getNumber().getDouble(*status);
+        }
+    }
+    return doubleVal;
 }
 
 U_CAPI const char* U_EXPORT2
@@ -388,79 +517,43 @@ U_CAPI int32_t U_EXPORT2
 unum_getAttribute(const UNumberFormat*          fmt,
           UNumberFormatAttribute  attr)
 {
-  if (((const NumberFormat*)fmt)->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
-    const DecimalFormat* df = (const DecimalFormat*) fmt;
-    switch(attr) {
-    case UNUM_PARSE_INT_ONLY:
-        return df->isParseIntegerOnly();
-        
-    case UNUM_GROUPING_USED:
-        return df->isGroupingUsed();
-        
-    case UNUM_DECIMAL_ALWAYS_SHOWN:
-        return df->isDecimalSeparatorAlwaysShown();    
-        
-    case UNUM_MAX_INTEGER_DIGITS:
-        return df->getMaximumIntegerDigits();
-        
-    case UNUM_MIN_INTEGER_DIGITS:
-        return df->getMinimumIntegerDigits();
-        
-    case UNUM_INTEGER_DIGITS:
-        // TBD: what should this return?
-        return df->getMinimumIntegerDigits();
-        
-    case UNUM_MAX_FRACTION_DIGITS:
-        return df->getMaximumFractionDigits();
-        
-    case UNUM_MIN_FRACTION_DIGITS:
-        return df->getMinimumFractionDigits();
-        
-    case UNUM_FRACTION_DIGITS:
-        // TBD: what should this return?
-        return df->getMinimumFractionDigits();
-        
-    case UNUM_SIGNIFICANT_DIGITS_USED:
-        return df->areSignificantDigitsUsed();
-        
-    case UNUM_MAX_SIGNIFICANT_DIGITS:
-        return df->getMaximumSignificantDigits();
-        
-    case UNUM_MIN_SIGNIFICANT_DIGITS:
-        return df->getMinimumSignificantDigits();
-        
-    case UNUM_MULTIPLIER:
-        return df->getMultiplier();    
-        
-    case UNUM_GROUPING_SIZE:
-        return df->getGroupingSize();    
-        
-    case UNUM_ROUNDING_MODE:
-        return df->getRoundingMode();
-        
-    case UNUM_FORMAT_WIDTH:
-        return df->getFormatWidth();
-        
-    case UNUM_PADDING_POSITION:
-        return df->getPadPosition();
-        
-    case UNUM_SECONDARY_GROUPING_SIZE:
-        return df->getSecondaryGroupingSize();
-        
-    default:
-        /* enums out of sync? unsupported enum? */
-        break;
-    }
-  } else {
-    U_ASSERT(((const NumberFormat*)fmt)->getDynamicClassID() == RuleBasedNumberFormat::getStaticClassID());
+    const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
     if (attr == UNUM_LENIENT_PARSE) {
-#if !UCONFIG_NO_COLLATION
-      return ((const RuleBasedNumberFormat*)fmt)->isLenient();
-#endif
+        // Supported for all subclasses
+        return nf->isLenient();
+    }
+    else if (attr == UNUM_MAX_INTEGER_DIGITS) {
+        return nf->getMaximumIntegerDigits();
+    }
+    else if (attr == UNUM_MIN_INTEGER_DIGITS) {
+        return nf->getMinimumIntegerDigits();
+    }
+    else if (attr == UNUM_INTEGER_DIGITS) {
+        // TODO: what should this return?
+        return nf->getMinimumIntegerDigits();
+    }
+    else if (attr == UNUM_MAX_FRACTION_DIGITS) {
+        return nf->getMaximumFractionDigits();
+    }
+    else if (attr == UNUM_MIN_FRACTION_DIGITS) {
+        return nf->getMinimumFractionDigits();
+    }
+    else if (attr == UNUM_FRACTION_DIGITS) {
+        // TODO: what should this return?
+        return nf->getMinimumFractionDigits();
+    }
+    else if (attr == UNUM_ROUNDING_MODE) {
+        return nf->getRoundingMode();
+    }
+
+    // The remaining attributes are only supported for DecimalFormat
+    const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
+    if (df != NULL) {
+        UErrorCode ignoredStatus = U_ZERO_ERROR;
+        return df->getAttribute(attr, ignoredStatus);
     }
-  }
 
-  return -1;
+    return -1;
 }
 
 U_CAPI void U_EXPORT2
@@ -468,105 +561,52 @@ unum_setAttribute(    UNumberFormat*          fmt,
             UNumberFormatAttribute  attr,
             int32_t                 newValue)
 {
-  if (((NumberFormat*)fmt)->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
-    DecimalFormat* df = (DecimalFormat*) fmt;
-    switch(attr) {
-    case UNUM_PARSE_INT_ONLY:
-        df->setParseIntegerOnly(newValue!=0);
-        break;
-        
-    case UNUM_GROUPING_USED:
-        df->setGroupingUsed(newValue!=0);
-        break;
-        
-    case UNUM_DECIMAL_ALWAYS_SHOWN:
-        df->setDecimalSeparatorAlwaysShown(newValue!=0);
-        break;
-        
-    case UNUM_MAX_INTEGER_DIGITS:
-        df->setMaximumIntegerDigits(newValue);
-        break;
-        
-    case UNUM_MIN_INTEGER_DIGITS:
-        df->setMinimumIntegerDigits(newValue);
-        break;
-        
-    case UNUM_INTEGER_DIGITS:
-        df->setMinimumIntegerDigits(newValue);
-        df->setMaximumIntegerDigits(newValue);
-        break;
-        
-    case UNUM_MAX_FRACTION_DIGITS:
-        df->setMaximumFractionDigits(newValue);
-        break;
-        
-    case UNUM_MIN_FRACTION_DIGITS:
-        df->setMinimumFractionDigits(newValue);
-        break;
-        
-    case UNUM_FRACTION_DIGITS:
-        df->setMinimumFractionDigits(newValue);
-        df->setMaximumFractionDigits(newValue);
-        break;
-        
-    case UNUM_SIGNIFICANT_DIGITS_USED:
-        df->setSignificantDigitsUsed(newValue!=0);
-        break;
-
-    case UNUM_MAX_SIGNIFICANT_DIGITS:
-        df->setMaximumSignificantDigits(newValue);
-        break;
-        
-    case UNUM_MIN_SIGNIFICANT_DIGITS:
-        df->setMinimumSignificantDigits(newValue);
-        break;
-        
-    case UNUM_MULTIPLIER:
-        df->setMultiplier(newValue);    
-        break;
-        
-    case UNUM_GROUPING_SIZE:
-        df->setGroupingSize(newValue);    
-        break;
-        
-    case UNUM_ROUNDING_MODE:
-        df->setRoundingMode((DecimalFormat::ERoundingMode)newValue);
-        break;
-        
-    case UNUM_FORMAT_WIDTH:
-        df->setFormatWidth(newValue);
-        break;
-        
-    case UNUM_PADDING_POSITION:
-        /** The position at which padding will take place. */
-        df->setPadPosition((DecimalFormat::EPadPosition)newValue);
-        break;
-        
-    case UNUM_SECONDARY_GROUPING_SIZE:
-        df->setSecondaryGroupingSize(newValue);
-        break;
-        
-    default:
-        /* Shouldn't get here anyway */
-        break;
-    }
-  } else {
-    U_ASSERT(((NumberFormat*)fmt)->getDynamicClassID() == RuleBasedNumberFormat::getStaticClassID());
+    NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
     if (attr == UNUM_LENIENT_PARSE) {
-#if !UCONFIG_NO_COLLATION
-      ((RuleBasedNumberFormat*)fmt)->setLenient((UBool)newValue);
-#endif
+        // Supported for all subclasses
+        // keep this here as the class may not be a DecimalFormat
+        return nf->setLenient(newValue != 0);
+    }
+    else if (attr == UNUM_MAX_INTEGER_DIGITS) {
+        return nf->setMaximumIntegerDigits(newValue);
+    }
+    else if (attr == UNUM_MIN_INTEGER_DIGITS) {
+        return nf->setMinimumIntegerDigits(newValue);
+    }
+    else if (attr == UNUM_INTEGER_DIGITS) {
+        nf->setMinimumIntegerDigits(newValue);
+        return nf->setMaximumIntegerDigits(newValue);
+    }
+    else if (attr == UNUM_MAX_FRACTION_DIGITS) {
+        return nf->setMaximumFractionDigits(newValue);
+    }
+    else if (attr == UNUM_MIN_FRACTION_DIGITS) {
+        return nf->setMinimumFractionDigits(newValue);
+    }
+    else if (attr == UNUM_FRACTION_DIGITS) {
+        nf->setMinimumFractionDigits(newValue);
+        return nf->setMaximumFractionDigits(newValue);
+    }
+    else if (attr == UNUM_ROUNDING_MODE) {
+        return nf->setRoundingMode((NumberFormat::ERoundingMode)newValue);
+    }
+
+    // The remaining attributes are only supported for DecimalFormat
+    DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
+    if (df != NULL) {
+        UErrorCode ignoredStatus = U_ZERO_ERROR;
+        df->setAttribute(attr, newValue, ignoredStatus);
     }
-  }
 }
 
 U_CAPI double U_EXPORT2
 unum_getDoubleAttribute(const UNumberFormat*          fmt,
           UNumberFormatAttribute  attr)
 {
-    if (((const NumberFormat*)fmt)->getDynamicClassID() == DecimalFormat::getStaticClassID() && 
-    attr == UNUM_ROUNDING_INCREMENT) {
-        return ((const DecimalFormat*)fmt)->getRoundingIncrement();
+    const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
+    const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
+    if (df != NULL &&  attr == UNUM_ROUNDING_INCREMENT) {
+        return df->getRoundingIncrement();
     } else {
         return -1.0;
     }
@@ -577,9 +617,10 @@ unum_setDoubleAttribute(    UNumberFormat*          fmt,
             UNumberFormatAttribute  attr,
             double                 newValue)
 {
-    if (((NumberFormat*)fmt)->getDynamicClassID() == DecimalFormat::getStaticClassID() && 
-    attr == UNUM_ROUNDING_INCREMENT) {   
-        ((DecimalFormat*)fmt)->setRoundingIncrement(newValue);
+    NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
+    DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
+    if (df != NULL && attr == UNUM_ROUNDING_INCREMENT) {   
+        df->setRoundingIncrement(newValue);
     }
 }
 
@@ -600,8 +641,9 @@ unum_getTextAttribute(const UNumberFormat*  fmt,
         res.setTo(result, 0, resultLength);
     }
 
-    if (((const NumberFormat*)fmt)->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
-        const DecimalFormat* df = (const DecimalFormat*) fmt;
+    const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
+    const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
+    if (df != NULL) {
         switch(tag) {
         case UNUM_POSITIVE_PREFIX:
             df->getPositivePrefix(res);
@@ -632,8 +674,8 @@ unum_getTextAttribute(const UNumberFormat*  fmt,
             return -1;
         }
     } else {
-        U_ASSERT(((const NumberFormat*)fmt)->getDynamicClassID() == RuleBasedNumberFormat::getStaticClassID());
-        const RuleBasedNumberFormat* rbnf = (const RuleBasedNumberFormat*)fmt;
+        const RuleBasedNumberFormat* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf);
+        U_ASSERT(rbnf != NULL);
         if (tag == UNUM_DEFAULT_RULESET) {
             res = rbnf->getDefaultRuleSetName();
         } else if (tag == UNUM_PUBLIC_RULESETS) {
@@ -660,12 +702,11 @@ unum_setTextAttribute(    UNumberFormat*                    fmt,
 {
     if(U_FAILURE(*status))
         return;
-    
-    int32_t len = (newValueLength == -1 ? u_strlen(newValue) : newValueLength);
-    const UnicodeString val((UChar*)newValue, len, len);
-    
-    if (((NumberFormat*)fmt)->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
-      DecimalFormat* df = (DecimalFormat*) fmt;
+
+    UnicodeString val(newValue, newValueLength);
+    NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
+    DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
+    if (df != NULL) {
       switch(tag) {
       case UNUM_POSITIVE_PREFIX:
         df->setPositivePrefix(val);
@@ -684,11 +725,11 @@ unum_setTextAttribute(    UNumberFormat*                    fmt,
         break;
         
       case UNUM_PADDING_CHARACTER:
-        df->setPadCharacter(*newValue);
+        df->setPadCharacter(val);
         break;
         
       case UNUM_CURRENCY_CODE:
-        df->setCurrency(newValue, *status);
+        df->setCurrency(val.getTerminatedBuffer(), *status);
         break;
         
       default:
@@ -696,11 +737,12 @@ unum_setTextAttribute(    UNumberFormat*                    fmt,
         break;
       }
     } else {
-      U_ASSERT(((NumberFormat*)fmt)->getDynamicClassID() == RuleBasedNumberFormat::getStaticClassID());
+      RuleBasedNumberFormat* rbnf = dynamic_cast<RuleBasedNumberFormat*>(nf);
+      U_ASSERT(rbnf != NULL);
       if (tag == UNUM_DEFAULT_RULESET) {
-    ((RuleBasedNumberFormat*)fmt)->setDefaultRuleSet(newValue, *status);
+        rbnf->setDefaultRuleSet(val, *status);
       } else {
-    *status = U_UNSUPPORTED_ERROR;
+        *status = U_UNSUPPORTED_ERROR;
       }
     }
 }
@@ -722,15 +764,17 @@ unum_toPattern(    const    UNumberFormat*          fmt,
         pat.setTo(result, 0, resultLength);
     }
 
-    if (((const NumberFormat*)fmt)->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
-      const DecimalFormat* df = (const DecimalFormat*) fmt;
+    const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
+    const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
+    if (df != NULL) {
       if(isPatternLocalized)
         df->toLocalizedPattern(pat);
       else
         df->toPattern(pat);
     } else {
-      U_ASSERT(((const NumberFormat*)fmt)->getDynamicClassID() == RuleBasedNumberFormat::getStaticClassID());
-      pat = ((const RuleBasedNumberFormat*)fmt)->getRules();
+      const RuleBasedNumberFormat* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf);
+      U_ASSERT(rbnf != NULL);
+      pat = rbnf->getRules();
     }
     return pat.extract(result, resultLength, *status);
 }
@@ -745,18 +789,18 @@ unum_getSymbol(const UNumberFormat *fmt,
     if(status==NULL || U_FAILURE(*status)) {
         return 0;
     }
-    
-    if(fmt==NULL || (uint16_t)symbol>=UNUM_FORMAT_SYMBOL_COUNT) {
+    if(fmt==NULL || symbol< 0 || symbol>=UNUM_FORMAT_SYMBOL_COUNT) {
         *status=U_ILLEGAL_ARGUMENT_ERROR;
         return 0;
     }
-
-    if (((const NumberFormat*)fmt)->getDynamicClassID() != DecimalFormat::getStaticClassID()) {
+    const NumberFormat *nf = reinterpret_cast<const NumberFormat *>(fmt);
+    const DecimalFormat *dcf = dynamic_cast<const DecimalFormat *>(nf);
+    if (dcf == NULL) {
       *status = U_UNSUPPORTED_ERROR;
       return 0;
     }
 
-    return ((const DecimalFormat *)fmt)->
+    return dcf->
       getDecimalFormatSymbols()->
         getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbol).
           extract(buffer, size, *status);
@@ -772,25 +816,25 @@ unum_setSymbol(UNumberFormat *fmt,
     if(status==NULL || U_FAILURE(*status)) {
         return;
     }
-    
-    if(fmt==NULL || (uint16_t)symbol>=UNUM_FORMAT_SYMBOL_COUNT || value==NULL || length<-1) {
+    if(fmt==NULL || symbol< 0 || symbol>=UNUM_FORMAT_SYMBOL_COUNT || value==NULL || length<-1) {
         *status=U_ILLEGAL_ARGUMENT_ERROR;
         return;
     }
-    
-    if (((NumberFormat*)fmt)->getDynamicClassID() != DecimalFormat::getStaticClassID()) {
+    NumberFormat *nf = reinterpret_cast<NumberFormat *>(fmt);
+    DecimalFormat *dcf = dynamic_cast<DecimalFormat *>(nf);
+    if (dcf == NULL) {
       *status = U_UNSUPPORTED_ERROR;
       return;
     }
 
-    DecimalFormatSymbols symbols(*((DecimalFormat *)fmt)->getDecimalFormatSymbols());
+    DecimalFormatSymbols symbols(*dcf->getDecimalFormatSymbols());
     symbols.setSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbol,
         UnicodeString(value, length));  /* UnicodeString can handle the case when length = -1. */
-    ((DecimalFormat *)fmt)->setDecimalFormatSymbols(symbols);
+    dcf->setDecimalFormatSymbols(symbols);
 }
 
 U_CAPI void U_EXPORT2
-unum_applyPattern(  UNumberFormat  *format,
+unum_applyPattern(  UNumberFormat  *fmt,
                     UBool          localized,
                     const UChar    *pattern,
                     int32_t        patternLength,
@@ -810,13 +854,15 @@ unum_applyPattern(  UNumberFormat  *format,
     
     int32_t len = (patternLength == -1 ? u_strlen(pattern) : patternLength);
     const UnicodeString pat((UChar*)pattern, len, len);
-    
+
     // Verify if the object passed is a DecimalFormat object
-    if (((NumberFormat*)format)->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
+    NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
+    DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
+    if (df != NULL) {
       if(localized) {
-        ((DecimalFormat*)format)->applyLocalizedPattern(pat,*parseError, *status);
+        df->applyLocalizedPattern(pat,*parseError, *status);
       } else {
-        ((DecimalFormat*)format)->applyPattern(pat,*parseError, *status);
+        df->applyPattern(pat,*parseError, *status);
       }
     } else {
       *status = U_UNSUPPORTED_ERROR;
@@ -838,4 +884,79 @@ unum_getLocaleByType(const UNumberFormat *fmt,
     return ((const Format*)fmt)->getLocaleID(type, *status);
 }
 
+U_CAPI void U_EXPORT2
+unum_setContext(UNumberFormat* fmt, UDisplayContext value, UErrorCode* status)
+{
+    if (U_FAILURE(*status)) {
+        return;
+    }
+    ((NumberFormat*)fmt)->setContext(value, *status);
+    return;
+}
+
+U_CAPI UDisplayContext U_EXPORT2
+unum_getContext(const UNumberFormat *fmt, UDisplayContextType type, UErrorCode* status)
+{
+    if (U_FAILURE(*status)) {
+        return (UDisplayContext)0;
+    }
+    return ((const NumberFormat*)fmt)->getContext(type, *status);
+}
+
+U_INTERNAL UFormattable * U_EXPORT2
+unum_parseToUFormattable(const UNumberFormat* fmt,
+                         UFormattable *result,
+                         const UChar* text,
+                         int32_t textLength,
+                         int32_t* parsePos, /* 0 = start */
+                         UErrorCode* status) {
+  UFormattable *newFormattable = NULL;
+  if (U_FAILURE(*status)) return result;
+  if (fmt == NULL || (text==NULL && textLength!=0)) {
+    *status = U_ILLEGAL_ARGUMENT_ERROR;
+    return result;
+  }
+  if (result == NULL) { // allocate if not allocated.
+    newFormattable = result = ufmt_open(status);
+  }
+  parseRes(*(Formattable::fromUFormattable(result)), fmt, text, textLength, parsePos, status);
+  if (U_FAILURE(*status) && newFormattable != NULL) {
+    ufmt_close(newFormattable);
+    result = NULL; // deallocate if there was a parse error
+  }
+  return result;
+}
+
+U_INTERNAL int32_t U_EXPORT2
+unum_formatUFormattable(const UNumberFormat* fmt,
+                        const UFormattable *number,
+                        UChar *result,
+                        int32_t resultLength,
+                        UFieldPosition *pos, /* ignored if 0 */
+                        UErrorCode *status) {
+    if (U_FAILURE(*status)) {
+      return 0;
+    }
+    if (fmt == NULL || number==NULL ||
+        (result==NULL ? resultLength!=0 : resultLength<0)) {
+      *status = U_ILLEGAL_ARGUMENT_ERROR;
+      return 0;
+    }
+    UnicodeString res(result, 0, resultLength);
+
+    FieldPosition fp;
+
+    if(pos != 0)
+        fp.setField(pos->field);
+
+    ((const NumberFormat*)fmt)->format(*(Formattable::fromUFormattable(number)), res, fp, *status);
+
+    if(pos != 0) {
+        pos->beginIndex = fp.getBeginIndex();
+        pos->endIndex = fp.getEndIndex();
+    }
+
+    return res.extract(result, resultLength, *status);
+}
+
 #endif /* #if !UCONFIG_NO_FORMATTING */