Home | History | Annotate | Download | only in i18n
      1 /*
      2 **********************************************************************
      3 * Copyright (c) 2004-2014, International Business Machines
      4 * Corporation and others.  All Rights Reserved.
      5 **********************************************************************
      6 * Author: Alan Liu
      7 * Created: April 20, 2004
      8 * Since: ICU 3.0
      9 **********************************************************************
     10 */
     11 #include "utypeinfo.h"  // for 'typeid' to work
     12 #include "unicode/utypes.h"
     13 
     14 #if !UCONFIG_NO_FORMATTING
     15 
     16 #include "unicode/measfmt.h"
     17 #include "unicode/numfmt.h"
     18 #include "currfmt.h"
     19 #include "unicode/localpointer.h"
     20 #include "simplepatternformatter.h"
     21 #include "quantityformatter.h"
     22 #include "unicode/plurrule.h"
     23 #include "unicode/decimfmt.h"
     24 #include "uresimp.h"
     25 #include "unicode/ures.h"
     26 #include "ureslocs.h"
     27 #include "cstring.h"
     28 #include "mutex.h"
     29 #include "ucln_in.h"
     30 #include "unicode/listformatter.h"
     31 #include "charstr.h"
     32 #include "unicode/putil.h"
     33 #include "unicode/smpdtfmt.h"
     34 #include "uassert.h"
     35 
     36 #include "sharednumberformat.h"
     37 #include "sharedpluralrules.h"
     38 #include "unifiedcache.h"
     39 
     40 #define MEAS_UNIT_COUNT 121
     41 #define WIDTH_INDEX_COUNT (UMEASFMT_WIDTH_NARROW + 1)
     42 
     43 U_NAMESPACE_BEGIN
     44 
     45 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MeasureFormat)
     46 
     47 // Used to format durations like 5:47 or 21:35:42.
     48 class NumericDateFormatters : public UMemory {
     49 public:
     50     // Formats like H:mm
     51     SimpleDateFormat hourMinute;
     52 
     53     // formats like M:ss
     54     SimpleDateFormat minuteSecond;
     55 
     56     // formats like H:mm:ss
     57     SimpleDateFormat hourMinuteSecond;
     58 
     59     // Constructor that takes the actual patterns for hour-minute,
     60     // minute-second, and hour-minute-second respectively.
     61     NumericDateFormatters(
     62             const UnicodeString &hm,
     63             const UnicodeString &ms,
     64             const UnicodeString &hms,
     65             UErrorCode &status) :
     66             hourMinute(hm, status),
     67             minuteSecond(ms, status),
     68             hourMinuteSecond(hms, status) {
     69         const TimeZone *gmt = TimeZone::getGMT();
     70         hourMinute.setTimeZone(*gmt);
     71         minuteSecond.setTimeZone(*gmt);
     72         hourMinuteSecond.setTimeZone(*gmt);
     73     }
     74 private:
     75     NumericDateFormatters(const NumericDateFormatters &other);
     76     NumericDateFormatters &operator=(const NumericDateFormatters &other);
     77 };
     78 
     79 // Instances contain all MeasureFormat specific data for a particular locale.
     80 // This data is cached. It is never copied, but is shared via shared pointers.
     81 class MeasureFormatCacheData : public SharedObject {
     82 public:
     83     QuantityFormatter formatters[MEAS_UNIT_COUNT][WIDTH_INDEX_COUNT];
     84     SimplePatternFormatter perFormatters[WIDTH_INDEX_COUNT];
     85 
     86     MeasureFormatCacheData();
     87     void adoptCurrencyFormat(int32_t widthIndex, NumberFormat *nfToAdopt) {
     88         delete currencyFormats[widthIndex];
     89         currencyFormats[widthIndex] = nfToAdopt;
     90     }
     91     const NumberFormat *getCurrencyFormat(int32_t widthIndex) const {
     92         return currencyFormats[widthIndex];
     93     }
     94     void adoptIntegerFormat(NumberFormat *nfToAdopt) {
     95         delete integerFormat;
     96         integerFormat = nfToAdopt;
     97     }
     98     const NumberFormat *getIntegerFormat() const {
     99         return integerFormat;
    100     }
    101     void adoptNumericDateFormatters(NumericDateFormatters *formattersToAdopt) {
    102         delete numericDateFormatters;
    103         numericDateFormatters = formattersToAdopt;
    104     }
    105     const NumericDateFormatters *getNumericDateFormatters() const {
    106         return numericDateFormatters;
    107     }
    108     void adoptPerUnitFormatter(
    109             int32_t index,
    110             int32_t widthIndex,
    111             SimplePatternFormatter *formatterToAdopt) {
    112         delete perUnitFormatters[index][widthIndex];
    113         perUnitFormatters[index][widthIndex] = formatterToAdopt;
    114     }
    115     const SimplePatternFormatter * const * getPerUnitFormattersByIndex(
    116             int32_t index) const {
    117         return perUnitFormatters[index];
    118     }
    119     virtual ~MeasureFormatCacheData();
    120 private:
    121     NumberFormat *currencyFormats[WIDTH_INDEX_COUNT];
    122     NumberFormat *integerFormat;
    123     NumericDateFormatters *numericDateFormatters;
    124     SimplePatternFormatter *perUnitFormatters[MEAS_UNIT_COUNT][WIDTH_INDEX_COUNT];
    125     MeasureFormatCacheData(const MeasureFormatCacheData &other);
    126     MeasureFormatCacheData &operator=(const MeasureFormatCacheData &other);
    127 };
    128 
    129 MeasureFormatCacheData::MeasureFormatCacheData() {
    130     for (int32_t i = 0; i < UPRV_LENGTHOF(currencyFormats); ++i) {
    131         currencyFormats[i] = NULL;
    132     }
    133     for (int32_t i = 0; i < MEAS_UNIT_COUNT; ++i) {
    134         for (int32_t j = 0; j < WIDTH_INDEX_COUNT; ++j) {
    135             perUnitFormatters[i][j] = NULL;
    136         }
    137     }
    138     integerFormat = NULL;
    139     numericDateFormatters = NULL;
    140 }
    141 
    142 MeasureFormatCacheData::~MeasureFormatCacheData() {
    143     for (int32_t i = 0; i < UPRV_LENGTHOF(currencyFormats); ++i) {
    144         delete currencyFormats[i];
    145     }
    146     for (int32_t i = 0; i < MEAS_UNIT_COUNT; ++i) {
    147         for (int32_t j = 0; j < WIDTH_INDEX_COUNT; ++j) {
    148             delete perUnitFormatters[i][j];
    149         }
    150     }
    151     delete integerFormat;
    152     delete numericDateFormatters;
    153 }
    154 
    155 static int32_t widthToIndex(UMeasureFormatWidth width) {
    156     if (width >= WIDTH_INDEX_COUNT) {
    157         return WIDTH_INDEX_COUNT - 1;
    158     }
    159     return width;
    160 }
    161 
    162 static UBool isCurrency(const MeasureUnit &unit) {
    163     return (uprv_strcmp(unit.getType(), "currency") == 0);
    164 }
    165 
    166 static UBool getString(
    167         const UResourceBundle *resource,
    168         UnicodeString &result,
    169         UErrorCode &status) {
    170     int32_t len = 0;
    171     const UChar *resStr = ures_getString(resource, &len, &status);
    172     if (U_FAILURE(status)) {
    173         return FALSE;
    174     }
    175     result.setTo(TRUE, resStr, len);
    176     return TRUE;
    177 }
    178 
    179 
    180 static UBool loadMeasureUnitData(
    181         const UResourceBundle *resource,
    182         MeasureFormatCacheData &cacheData,
    183         UErrorCode &status) {
    184     if (U_FAILURE(status)) {
    185         return FALSE;
    186     }
    187     static const char *widthPath[] = {"units", "unitsShort", "unitsNarrow"};
    188     MeasureUnit *units = NULL;
    189     int32_t unitCount = MeasureUnit::getAvailable(units, 0, status);
    190     while (status == U_BUFFER_OVERFLOW_ERROR) {
    191         status = U_ZERO_ERROR;
    192         delete [] units;
    193         units = new MeasureUnit[unitCount];
    194         if (units == NULL) {
    195             status = U_MEMORY_ALLOCATION_ERROR;
    196             return FALSE;
    197         }
    198         unitCount = MeasureUnit::getAvailable(units, unitCount, status);
    199     }
    200     for (int32_t currentWidth = 0; currentWidth < WIDTH_INDEX_COUNT; ++currentWidth) {
    201         // Be sure status is clear since next resource bundle lookup may fail.
    202         if (U_FAILURE(status)) {
    203             delete [] units;
    204             return FALSE;
    205         }
    206         LocalUResourceBundlePointer widthBundle(
    207                 ures_getByKeyWithFallback(
    208                         resource, widthPath[currentWidth], NULL, &status));
    209         // We may not have data for all widths in all locales.
    210         if (status == U_MISSING_RESOURCE_ERROR) {
    211             status = U_ZERO_ERROR;
    212             continue;
    213         }
    214         {
    215             // compound per
    216             LocalUResourceBundlePointer compoundPerBundle(
    217                     ures_getByKeyWithFallback(
    218                             widthBundle.getAlias(),
    219                             "compound/per",
    220                             NULL,
    221                             &status));
    222             if (U_FAILURE(status)) {
    223                 status = U_ZERO_ERROR;
    224             } else {
    225                 UnicodeString perPattern;
    226                 getString(compoundPerBundle.getAlias(), perPattern, status);
    227                 cacheData.perFormatters[currentWidth].compile(perPattern, status);
    228             }
    229         }
    230         for (int32_t currentUnit = 0; currentUnit < unitCount; ++currentUnit) {
    231             // Be sure status is clear next lookup may fail.
    232             if (U_FAILURE(status)) {
    233                 delete [] units;
    234                 return FALSE;
    235             }
    236             if (isCurrency(units[currentUnit])) {
    237                 continue;
    238             }
    239             CharString pathBuffer;
    240             pathBuffer.append(units[currentUnit].getType(), status)
    241                     .append("/", status)
    242                     .append(units[currentUnit].getSubtype(), status);
    243             LocalUResourceBundlePointer unitBundle(
    244                     ures_getByKeyWithFallback(
    245                             widthBundle.getAlias(),
    246                             pathBuffer.data(),
    247                             NULL,
    248                             &status));
    249             // We may not have data for all units in all widths
    250             if (status == U_MISSING_RESOURCE_ERROR) {
    251                 status = U_ZERO_ERROR;
    252                 continue;
    253             }
    254             // We must have the unit bundle to proceed
    255             if (U_FAILURE(status)) {
    256                 delete [] units;
    257                 return FALSE;
    258             }
    259             int32_t size = ures_getSize(unitBundle.getAlias());
    260             for (int32_t plIndex = 0; plIndex < size; ++plIndex) {
    261                 LocalUResourceBundlePointer pluralBundle(
    262                         ures_getByIndex(
    263                                 unitBundle.getAlias(), plIndex, NULL, &status));
    264                 if (U_FAILURE(status)) {
    265                     delete [] units;
    266                     return FALSE;
    267                 }
    268                 const char * resKey = ures_getKey(pluralBundle.getAlias());
    269                 if (uprv_strcmp(resKey, "dnam") == 0) {
    270                     continue; // skip display name & per pattern (new in CLDR 26 / ICU 54) for now, not part of plurals
    271                 }
    272                 if (uprv_strcmp(resKey, "per") == 0) {
    273                     UnicodeString perPattern;
    274                     getString(pluralBundle.getAlias(), perPattern, status);
    275                     cacheData.adoptPerUnitFormatter(
    276                             units[currentUnit].getIndex(),
    277                             currentWidth,
    278                             new SimplePatternFormatter(perPattern));
    279                     continue;
    280                 }
    281                 UnicodeString rawPattern;
    282                 getString(pluralBundle.getAlias(), rawPattern, status);
    283                 cacheData.formatters[units[currentUnit].getIndex()][currentWidth].add(
    284                         resKey,
    285                         rawPattern,
    286                         status);
    287             }
    288         }
    289     }
    290     delete [] units;
    291     return U_SUCCESS(status);
    292 }
    293 
    294 static UnicodeString loadNumericDateFormatterPattern(
    295         const UResourceBundle *resource,
    296         const char *pattern,
    297         UErrorCode &status) {
    298     UnicodeString result;
    299     if (U_FAILURE(status)) {
    300         return result;
    301     }
    302     CharString chs;
    303     chs.append("durationUnits", status)
    304             .append("/", status).append(pattern, status);
    305     LocalUResourceBundlePointer patternBundle(
    306             ures_getByKeyWithFallback(
    307                 resource,
    308                 chs.data(),
    309                 NULL,
    310                 &status));
    311     if (U_FAILURE(status)) {
    312         return result;
    313     }
    314     getString(patternBundle.getAlias(), result, status);
    315     // Replace 'h' with 'H'
    316     int32_t len = result.length();
    317     UChar *buffer = result.getBuffer(len);
    318     for (int32_t i = 0; i < len; ++i) {
    319         if (buffer[i] == 0x68) { // 'h'
    320             buffer[i] = 0x48; // 'H'
    321         }
    322     }
    323     result.releaseBuffer(len);
    324     return result;
    325 }
    326 
    327 static NumericDateFormatters *loadNumericDateFormatters(
    328         const UResourceBundle *resource,
    329         UErrorCode &status) {
    330     if (U_FAILURE(status)) {
    331         return NULL;
    332     }
    333     NumericDateFormatters *result = new NumericDateFormatters(
    334         loadNumericDateFormatterPattern(resource, "hm", status),
    335         loadNumericDateFormatterPattern(resource, "ms", status),
    336         loadNumericDateFormatterPattern(resource, "hms", status),
    337         status);
    338     if (U_FAILURE(status)) {
    339         delete result;
    340         return NULL;
    341     }
    342     return result;
    343 }
    344 
    345 template<> U_I18N_API
    346 const MeasureFormatCacheData *LocaleCacheKey<MeasureFormatCacheData>::createObject(
    347         const void * /*unused*/, UErrorCode &status) const {
    348     const char *localeId = fLoc.getName();
    349     LocalUResourceBundlePointer unitsBundle(ures_open(U_ICUDATA_UNIT, localeId, &status));
    350     static UNumberFormatStyle currencyStyles[] = {
    351             UNUM_CURRENCY_PLURAL, UNUM_CURRENCY_ISO, UNUM_CURRENCY};
    352     LocalPointer<MeasureFormatCacheData> result(new MeasureFormatCacheData(), status);
    353     if (U_FAILURE(status)) {
    354         return NULL;
    355     }
    356     if (!loadMeasureUnitData(
    357             unitsBundle.getAlias(),
    358             *result,
    359             status)) {
    360         return NULL;
    361     }
    362     result->adoptNumericDateFormatters(loadNumericDateFormatters(
    363             unitsBundle.getAlias(), status));
    364     if (U_FAILURE(status)) {
    365         return NULL;
    366     }
    367 
    368     for (int32_t i = 0; i < WIDTH_INDEX_COUNT; ++i) {
    369         result->adoptCurrencyFormat(i, NumberFormat::createInstance(
    370                 localeId, currencyStyles[i], status));
    371         if (U_FAILURE(status)) {
    372             return NULL;
    373         }
    374     }
    375     NumberFormat *inf = NumberFormat::createInstance(
    376             localeId, UNUM_DECIMAL, status);
    377     if (U_FAILURE(status)) {
    378         return NULL;
    379     }
    380     inf->setMaximumFractionDigits(0);
    381     DecimalFormat *decfmt = dynamic_cast<DecimalFormat *>(inf);
    382     if (decfmt != NULL) {
    383         decfmt->setRoundingMode(DecimalFormat::kRoundDown);
    384     }
    385     result->adoptIntegerFormat(inf);
    386     result->addRef();
    387     return result.orphan();
    388 }
    389 
    390 static UBool isTimeUnit(const MeasureUnit &mu, const char *tu) {
    391     return uprv_strcmp(mu.getType(), "duration") == 0 &&
    392             uprv_strcmp(mu.getSubtype(), tu) == 0;
    393 }
    394 
    395 // Converts a composite measure into hours-minutes-seconds and stores at hms
    396 // array. [0] is hours; [1] is minutes; [2] is seconds. Returns a bit map of
    397 // units found: 1=hours, 2=minutes, 4=seconds. For example, if measures
    398 // contains hours-minutes, this function would return 3.
    399 //
    400 // If measures cannot be converted into hours, minutes, seconds or if amounts
    401 // are negative, or if hours, minutes, seconds are out of order, returns 0.
    402 static int32_t toHMS(
    403         const Measure *measures,
    404         int32_t measureCount,
    405         Formattable *hms,
    406         UErrorCode &status) {
    407     if (U_FAILURE(status)) {
    408         return 0;
    409     }
    410     int32_t result = 0;
    411     if (U_FAILURE(status)) {
    412         return 0;
    413     }
    414     // We use copy constructor to ensure that both sides of equality operator
    415     // are instances of MeasureUnit base class and not a subclass. Otherwise,
    416     // operator== will immediately return false.
    417     for (int32_t i = 0; i < measureCount; ++i) {
    418         if (isTimeUnit(measures[i].getUnit(), "hour")) {
    419             // hour must come first
    420             if (result >= 1) {
    421                 return 0;
    422             }
    423             hms[0] = measures[i].getNumber();
    424             if (hms[0].getDouble() < 0.0) {
    425                 return 0;
    426             }
    427             result |= 1;
    428         } else if (isTimeUnit(measures[i].getUnit(), "minute")) {
    429             // minute must come after hour
    430             if (result >= 2) {
    431                 return 0;
    432             }
    433             hms[1] = measures[i].getNumber();
    434             if (hms[1].getDouble() < 0.0) {
    435                 return 0;
    436             }
    437             result |= 2;
    438         } else if (isTimeUnit(measures[i].getUnit(), "second")) {
    439             // second must come after hour and minute
    440             if (result >= 4) {
    441                 return 0;
    442             }
    443             hms[2] = measures[i].getNumber();
    444             if (hms[2].getDouble() < 0.0) {
    445                 return 0;
    446             }
    447             result |= 4;
    448         } else {
    449             return 0;
    450         }
    451     }
    452     return result;
    453 }
    454 
    455 
    456 MeasureFormat::MeasureFormat(
    457         const Locale &locale, UMeasureFormatWidth w, UErrorCode &status)
    458         : cache(NULL),
    459           numberFormat(NULL),
    460           pluralRules(NULL),
    461           width(w),
    462           listFormatter(NULL) {
    463     initMeasureFormat(locale, w, NULL, status);
    464 }
    465 
    466 MeasureFormat::MeasureFormat(
    467         const Locale &locale,
    468         UMeasureFormatWidth w,
    469         NumberFormat *nfToAdopt,
    470         UErrorCode &status)
    471         : cache(NULL),
    472           numberFormat(NULL),
    473           pluralRules(NULL),
    474           width(w),
    475           listFormatter(NULL) {
    476     initMeasureFormat(locale, w, nfToAdopt, status);
    477 }
    478 
    479 MeasureFormat::MeasureFormat(const MeasureFormat &other) :
    480         Format(other),
    481         cache(other.cache),
    482         numberFormat(other.numberFormat),
    483         pluralRules(other.pluralRules),
    484         width(other.width),
    485         listFormatter(NULL) {
    486     cache->addRef();
    487     numberFormat->addRef();
    488     pluralRules->addRef();
    489     listFormatter = new ListFormatter(*other.listFormatter);
    490 }
    491 
    492 MeasureFormat &MeasureFormat::operator=(const MeasureFormat &other) {
    493     if (this == &other) {
    494         return *this;
    495     }
    496     Format::operator=(other);
    497     SharedObject::copyPtr(other.cache, cache);
    498     SharedObject::copyPtr(other.numberFormat, numberFormat);
    499     SharedObject::copyPtr(other.pluralRules, pluralRules);
    500     width = other.width;
    501     delete listFormatter;
    502     listFormatter = new ListFormatter(*other.listFormatter);
    503     return *this;
    504 }
    505 
    506 MeasureFormat::MeasureFormat() :
    507         cache(NULL),
    508         numberFormat(NULL),
    509         pluralRules(NULL),
    510         width(UMEASFMT_WIDTH_WIDE),
    511         listFormatter(NULL) {
    512 }
    513 
    514 MeasureFormat::~MeasureFormat() {
    515     if (cache != NULL) {
    516         cache->removeRef();
    517     }
    518     if (numberFormat != NULL) {
    519         numberFormat->removeRef();
    520     }
    521     if (pluralRules != NULL) {
    522         pluralRules->removeRef();
    523     }
    524     delete listFormatter;
    525 }
    526 
    527 UBool MeasureFormat::operator==(const Format &other) const {
    528     if (this == &other) { // Same object, equal
    529         return TRUE;
    530     }
    531     if (!Format::operator==(other)) {
    532         return FALSE;
    533     }
    534     const MeasureFormat &rhs = static_cast<const MeasureFormat &>(other);
    535 
    536     // Note: Since the ListFormatter depends only on Locale and width, we
    537     // don't have to check it here.
    538 
    539     // differing widths aren't equivalent
    540     if (width != rhs.width) {
    541         return FALSE;
    542     }
    543     // Width the same check locales.
    544     // We don't need to check locales if both objects have same cache.
    545     if (cache != rhs.cache) {
    546         UErrorCode status = U_ZERO_ERROR;
    547         const char *localeId = getLocaleID(status);
    548         const char *rhsLocaleId = rhs.getLocaleID(status);
    549         if (U_FAILURE(status)) {
    550             // On failure, assume not equal
    551             return FALSE;
    552         }
    553         if (uprv_strcmp(localeId, rhsLocaleId) != 0) {
    554             return FALSE;
    555         }
    556     }
    557     // Locales same, check NumberFormat if shared data differs.
    558     return (
    559             numberFormat == rhs.numberFormat ||
    560             **numberFormat == **rhs.numberFormat);
    561 }
    562 
    563 Format *MeasureFormat::clone() const {
    564     return new MeasureFormat(*this);
    565 }
    566 
    567 UnicodeString &MeasureFormat::format(
    568         const Formattable &obj,
    569         UnicodeString &appendTo,
    570         FieldPosition &pos,
    571         UErrorCode &status) const {
    572     if (U_FAILURE(status)) return appendTo;
    573     if (obj.getType() == Formattable::kObject) {
    574         const UObject* formatObj = obj.getObject();
    575         const Measure* amount = dynamic_cast<const Measure*>(formatObj);
    576         if (amount != NULL) {
    577             return formatMeasure(
    578                     *amount, **numberFormat, appendTo, pos, status);
    579         }
    580     }
    581     status = U_ILLEGAL_ARGUMENT_ERROR;
    582     return appendTo;
    583 }
    584 
    585 void MeasureFormat::parseObject(
    586         const UnicodeString & /*source*/,
    587         Formattable & /*result*/,
    588         ParsePosition& /*pos*/) const {
    589     return;
    590 }
    591 
    592 UnicodeString &MeasureFormat::formatMeasurePerUnit(
    593         const Measure &measure,
    594         const MeasureUnit &perUnit,
    595         UnicodeString &appendTo,
    596         FieldPosition &pos,
    597         UErrorCode &status) const {
    598     if (U_FAILURE(status)) {
    599         return appendTo;
    600     }
    601     MeasureUnit *resolvedUnit =
    602             MeasureUnit::resolveUnitPerUnit(measure.getUnit(), perUnit);
    603     if (resolvedUnit != NULL) {
    604         Measure newMeasure(measure.getNumber(), resolvedUnit, status);
    605         return formatMeasure(
    606                 newMeasure, **numberFormat, appendTo, pos, status);
    607     }
    608     FieldPosition fpos(pos.getField());
    609     UnicodeString result;
    610     int32_t offset = withPerUnitAndAppend(
    611             formatMeasure(
    612                     measure, **numberFormat, result, fpos, status),
    613             perUnit,
    614             appendTo,
    615             status);
    616     if (U_FAILURE(status)) {
    617         return appendTo;
    618     }
    619     if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) {
    620         pos.setBeginIndex(fpos.getBeginIndex() + offset);
    621         pos.setEndIndex(fpos.getEndIndex() + offset);
    622     }
    623     return appendTo;
    624 }
    625 
    626 UnicodeString &MeasureFormat::formatMeasures(
    627         const Measure *measures,
    628         int32_t measureCount,
    629         UnicodeString &appendTo,
    630         FieldPosition &pos,
    631         UErrorCode &status) const {
    632     if (U_FAILURE(status)) {
    633         return appendTo;
    634     }
    635     if (measureCount == 0) {
    636         return appendTo;
    637     }
    638     if (measureCount == 1) {
    639         return formatMeasure(measures[0], **numberFormat, appendTo, pos, status);
    640     }
    641     if (width == UMEASFMT_WIDTH_NUMERIC) {
    642         Formattable hms[3];
    643         int32_t bitMap = toHMS(measures, measureCount, hms, status);
    644         if (bitMap > 0) {
    645             return formatNumeric(hms, bitMap, appendTo, status);
    646         }
    647     }
    648     if (pos.getField() != FieldPosition::DONT_CARE) {
    649         return formatMeasuresSlowTrack(
    650                 measures, measureCount, appendTo, pos, status);
    651     }
    652     UnicodeString *results = new UnicodeString[measureCount];
    653     if (results == NULL) {
    654         status = U_MEMORY_ALLOCATION_ERROR;
    655         return appendTo;
    656     }
    657     for (int32_t i = 0; i < measureCount; ++i) {
    658         const NumberFormat *nf = cache->getIntegerFormat();
    659         if (i == measureCount - 1) {
    660             nf = numberFormat->get();
    661         }
    662         formatMeasure(
    663                 measures[i],
    664                 *nf,
    665                 results[i],
    666                 pos,
    667                 status);
    668     }
    669     listFormatter->format(results, measureCount, appendTo, status);
    670     delete [] results;
    671     return appendTo;
    672 }
    673 
    674 void MeasureFormat::initMeasureFormat(
    675         const Locale &locale,
    676         UMeasureFormatWidth w,
    677         NumberFormat *nfToAdopt,
    678         UErrorCode &status) {
    679     static const char *listStyles[] = {"unit", "unit-short", "unit-narrow"};
    680     LocalPointer<NumberFormat> nf(nfToAdopt);
    681     if (U_FAILURE(status)) {
    682         return;
    683     }
    684     const char *name = locale.getName();
    685     setLocaleIDs(name, name);
    686 
    687     UnifiedCache::getByLocale(locale, cache, status);
    688     if (U_FAILURE(status)) {
    689         return;
    690     }
    691 
    692     const SharedPluralRules *pr = PluralRules::createSharedInstance(
    693             locale, UPLURAL_TYPE_CARDINAL, status);
    694     if (U_FAILURE(status)) {
    695         return;
    696     }
    697     SharedObject::copyPtr(pr, pluralRules);
    698     pr->removeRef();
    699     if (nf.isNull()) {
    700         const SharedNumberFormat *shared = NumberFormat::createSharedInstance(
    701                 locale, UNUM_DECIMAL, status);
    702         if (U_FAILURE(status)) {
    703             return;
    704         }
    705         SharedObject::copyPtr(shared, numberFormat);
    706         shared->removeRef();
    707     } else {
    708         adoptNumberFormat(nf.orphan(), status);
    709         if (U_FAILURE(status)) {
    710             return;
    711         }
    712     }
    713     width = w;
    714     delete listFormatter;
    715     listFormatter = ListFormatter::createInstance(
    716             locale,
    717             listStyles[widthToIndex(width)],
    718             status);
    719 }
    720 
    721 void MeasureFormat::adoptNumberFormat(
    722         NumberFormat *nfToAdopt, UErrorCode &status) {
    723     LocalPointer<NumberFormat> nf(nfToAdopt);
    724     if (U_FAILURE(status)) {
    725         return;
    726     }
    727     SharedNumberFormat *shared = new SharedNumberFormat(nf.getAlias());
    728     if (shared == NULL) {
    729         status = U_MEMORY_ALLOCATION_ERROR;
    730         return;
    731     }
    732     nf.orphan();
    733     SharedObject::copyPtr(shared, numberFormat);
    734 }
    735 
    736 UBool MeasureFormat::setMeasureFormatLocale(const Locale &locale, UErrorCode &status) {
    737     if (U_FAILURE(status) || locale == getLocale(status)) {
    738         return FALSE;
    739     }
    740     initMeasureFormat(locale, width, NULL, status);
    741     return U_SUCCESS(status);
    742 }
    743 
    744 const NumberFormat &MeasureFormat::getNumberFormat() const {
    745     return **numberFormat;
    746 }
    747 
    748 const PluralRules &MeasureFormat::getPluralRules() const {
    749     return **pluralRules;
    750 }
    751 
    752 Locale MeasureFormat::getLocale(UErrorCode &status) const {
    753     return Format::getLocale(ULOC_VALID_LOCALE, status);
    754 }
    755 
    756 const char *MeasureFormat::getLocaleID(UErrorCode &status) const {
    757     return Format::getLocaleID(ULOC_VALID_LOCALE, status);
    758 }
    759 
    760 UnicodeString &MeasureFormat::formatMeasure(
    761         const Measure &measure,
    762         const NumberFormat &nf,
    763         UnicodeString &appendTo,
    764         FieldPosition &pos,
    765         UErrorCode &status) const {
    766     if (U_FAILURE(status)) {
    767         return appendTo;
    768     }
    769     const Formattable& amtNumber = measure.getNumber();
    770     const MeasureUnit& amtUnit = measure.getUnit();
    771     if (isCurrency(amtUnit)) {
    772         UChar isoCode[4];
    773         u_charsToUChars(amtUnit.getSubtype(), isoCode, 4);
    774         return cache->getCurrencyFormat(widthToIndex(width))->format(
    775                 new CurrencyAmount(amtNumber, isoCode, status),
    776                 appendTo,
    777                 pos,
    778                 status);
    779     }
    780     const QuantityFormatter *quantityFormatter = getQuantityFormatter(
    781             amtUnit.getIndex(), widthToIndex(width), status);
    782     if (U_FAILURE(status)) {
    783         return appendTo;
    784     }
    785     return quantityFormatter->format(
    786             amtNumber,
    787             nf,
    788             **pluralRules,
    789             appendTo,
    790             pos,
    791             status);
    792 }
    793 
    794 // Formats hours-minutes-seconds as 5:37:23 or similar.
    795 UnicodeString &MeasureFormat::formatNumeric(
    796         const Formattable *hms,  // always length 3
    797         int32_t bitMap,   // 1=hourset, 2=minuteset, 4=secondset
    798         UnicodeString &appendTo,
    799         UErrorCode &status) const {
    800     if (U_FAILURE(status)) {
    801         return appendTo;
    802     }
    803     UDate millis =
    804         (UDate) (((uprv_trunc(hms[0].getDouble(status)) * 60.0
    805              + uprv_trunc(hms[1].getDouble(status))) * 60.0
    806                   + uprv_trunc(hms[2].getDouble(status))) * 1000.0);
    807     switch (bitMap) {
    808     case 5: // hs
    809     case 7: // hms
    810         return formatNumeric(
    811                 millis,
    812                 cache->getNumericDateFormatters()->hourMinuteSecond,
    813                 UDAT_SECOND_FIELD,
    814                 hms[2],
    815                 appendTo,
    816                 status);
    817         break;
    818     case 6: // ms
    819         return formatNumeric(
    820                 millis,
    821                 cache->getNumericDateFormatters()->minuteSecond,
    822                 UDAT_SECOND_FIELD,
    823                 hms[2],
    824                 appendTo,
    825                 status);
    826         break;
    827     case 3: // hm
    828         return formatNumeric(
    829                 millis,
    830                 cache->getNumericDateFormatters()->hourMinute,
    831                 UDAT_MINUTE_FIELD,
    832                 hms[1],
    833                 appendTo,
    834                 status);
    835         break;
    836     default:
    837         status = U_INTERNAL_PROGRAM_ERROR;
    838         return appendTo;
    839         break;
    840     }
    841     return appendTo;
    842 }
    843 
    844 static void appendRange(
    845         const UnicodeString &src,
    846         int32_t start,
    847         int32_t end,
    848         UnicodeString &dest) {
    849     dest.append(src, start, end - start);
    850 }
    851 
    852 static void appendRange(
    853         const UnicodeString &src,
    854         int32_t end,
    855         UnicodeString &dest) {
    856     dest.append(src, end, src.length() - end);
    857 }
    858 
    859 // Formats time like 5:37:23
    860 UnicodeString &MeasureFormat::formatNumeric(
    861         UDate date, // Time since epoch 1:30:00 would be 5400000
    862         const DateFormat &dateFmt, // h:mm, m:ss, or h:mm:ss
    863         UDateFormatField smallestField, // seconds in 5:37:23.5
    864         const Formattable &smallestAmount, // 23.5 for 5:37:23.5
    865         UnicodeString &appendTo,
    866         UErrorCode &status) const {
    867     if (U_FAILURE(status)) {
    868         return appendTo;
    869     }
    870     // Format the smallest amount with this object's NumberFormat
    871     UnicodeString smallestAmountFormatted;
    872 
    873     // We keep track of the integer part of smallest amount so that
    874     // we can replace it later so that we get '0:00:09.3' instead of
    875     // '0:00:9.3'
    876     FieldPosition intFieldPosition(UNUM_INTEGER_FIELD);
    877     (*numberFormat)->format(
    878             smallestAmount, smallestAmountFormatted, intFieldPosition, status);
    879     if (
    880             intFieldPosition.getBeginIndex() == 0 &&
    881             intFieldPosition.getEndIndex() == 0) {
    882         status = U_INTERNAL_PROGRAM_ERROR;
    883         return appendTo;
    884     }
    885 
    886     // Format time. draft becomes something like '5:30:45'
    887     FieldPosition smallestFieldPosition(smallestField);
    888     UnicodeString draft;
    889     dateFmt.format(date, draft, smallestFieldPosition, status);
    890 
    891     // If we find field for smallest amount replace it with the formatted
    892     // smallest amount from above taking care to replace the integer part
    893     // with what is in original time. For example, If smallest amount
    894     // is 9.35s and the formatted time is 0:00:09 then 9.35 becomes 09.35
    895     // and replacing yields 0:00:09.35
    896     if (smallestFieldPosition.getBeginIndex() != 0 ||
    897             smallestFieldPosition.getEndIndex() != 0) {
    898         appendRange(draft, 0, smallestFieldPosition.getBeginIndex(), appendTo);
    899         appendRange(
    900                 smallestAmountFormatted,
    901                 0,
    902                 intFieldPosition.getBeginIndex(),
    903                 appendTo);
    904         appendRange(
    905                 draft,
    906                 smallestFieldPosition.getBeginIndex(),
    907                 smallestFieldPosition.getEndIndex(),
    908                 appendTo);
    909         appendRange(
    910                 smallestAmountFormatted,
    911                 intFieldPosition.getEndIndex(),
    912                 appendTo);
    913         appendRange(
    914                 draft,
    915                 smallestFieldPosition.getEndIndex(),
    916                 appendTo);
    917     } else {
    918         appendTo.append(draft);
    919     }
    920     return appendTo;
    921 }
    922 
    923 const QuantityFormatter *MeasureFormat::getQuantityFormatter(
    924         int32_t index,
    925         int32_t widthIndex,
    926         UErrorCode &status) const {
    927     if (U_FAILURE(status)) {
    928         return NULL;
    929     }
    930     const QuantityFormatter *formatters =
    931             cache->formatters[index];
    932     if (formatters[widthIndex].isValid()) {
    933         return &formatters[widthIndex];
    934     }
    935     if (formatters[UMEASFMT_WIDTH_SHORT].isValid()) {
    936         return &formatters[UMEASFMT_WIDTH_SHORT];
    937     }
    938     if (formatters[UMEASFMT_WIDTH_WIDE].isValid()) {
    939         return &formatters[UMEASFMT_WIDTH_WIDE];
    940     }
    941     status = U_MISSING_RESOURCE_ERROR;
    942     return NULL;
    943 }
    944 
    945 const SimplePatternFormatter *MeasureFormat::getPerUnitFormatter(
    946         int32_t index,
    947         int32_t widthIndex) const {
    948     const SimplePatternFormatter * const * perUnitFormatters =
    949             cache->getPerUnitFormattersByIndex(index);
    950     if (perUnitFormatters[widthIndex] != NULL) {
    951         return perUnitFormatters[widthIndex];
    952     }
    953     if (perUnitFormatters[UMEASFMT_WIDTH_SHORT] != NULL) {
    954         return perUnitFormatters[UMEASFMT_WIDTH_SHORT];
    955     }
    956     if (perUnitFormatters[UMEASFMT_WIDTH_WIDE] != NULL) {
    957         return perUnitFormatters[UMEASFMT_WIDTH_WIDE];
    958     }
    959     return NULL;
    960 }
    961 
    962 const SimplePatternFormatter *MeasureFormat::getPerFormatter(
    963         int32_t widthIndex,
    964         UErrorCode &status) const {
    965     if (U_FAILURE(status)) {
    966         return NULL;
    967     }
    968     const SimplePatternFormatter * perFormatters = cache->perFormatters;
    969 
    970     if (perFormatters[widthIndex].getPlaceholderCount() == 2) {
    971         return &perFormatters[widthIndex];
    972     }
    973     if (perFormatters[UMEASFMT_WIDTH_SHORT].getPlaceholderCount() == 2) {
    974         return &perFormatters[UMEASFMT_WIDTH_SHORT];
    975     }
    976     if (perFormatters[UMEASFMT_WIDTH_WIDE].getPlaceholderCount() == 2) {
    977         return &perFormatters[UMEASFMT_WIDTH_WIDE];
    978     }
    979     status = U_MISSING_RESOURCE_ERROR;
    980     return NULL;
    981 }
    982 
    983 static void getPerUnitString(
    984         const QuantityFormatter &formatter,
    985         UnicodeString &result) {
    986     result = formatter.getByVariant("one")->getPatternWithNoPlaceholders();
    987     result.trim();
    988 }
    989 
    990 int32_t MeasureFormat::withPerUnitAndAppend(
    991         const UnicodeString &formatted,
    992         const MeasureUnit &perUnit,
    993         UnicodeString &appendTo,
    994         UErrorCode &status) const {
    995     int32_t offset = -1;
    996     if (U_FAILURE(status)) {
    997         return offset;
    998     }
    999     const SimplePatternFormatter *perUnitFormatter = getPerUnitFormatter(
   1000             perUnit.getIndex(), widthToIndex(width));
   1001     if (perUnitFormatter != NULL) {
   1002         const UnicodeString *params[] = {&formatted};
   1003         perUnitFormatter->formatAndAppend(
   1004                 params,
   1005                 UPRV_LENGTHOF(params),
   1006                 appendTo,
   1007                 &offset,
   1008                 1,
   1009                 status);
   1010         return offset;
   1011     }
   1012     const SimplePatternFormatter *perFormatter = getPerFormatter(
   1013             widthToIndex(width), status);
   1014     const QuantityFormatter *qf = getQuantityFormatter(
   1015             perUnit.getIndex(), widthToIndex(width), status);
   1016     if (U_FAILURE(status)) {
   1017         return offset;
   1018     }
   1019     UnicodeString perUnitString;
   1020     getPerUnitString(*qf, perUnitString);
   1021     const UnicodeString *params[] = {&formatted, &perUnitString};
   1022     perFormatter->formatAndAppend(
   1023             params,
   1024             UPRV_LENGTHOF(params),
   1025             appendTo,
   1026             &offset,
   1027             1,
   1028             status);
   1029     return offset;
   1030 }
   1031 
   1032 UnicodeString &MeasureFormat::formatMeasuresSlowTrack(
   1033         const Measure *measures,
   1034         int32_t measureCount,
   1035         UnicodeString& appendTo,
   1036         FieldPosition& pos,
   1037         UErrorCode& status) const {
   1038     if (U_FAILURE(status)) {
   1039         return appendTo;
   1040     }
   1041     FieldPosition dontCare(FieldPosition::DONT_CARE);
   1042     FieldPosition fpos(pos.getField());
   1043     UnicodeString *results = new UnicodeString[measureCount];
   1044     int32_t fieldPositionFoundIndex = -1;
   1045     for (int32_t i = 0; i < measureCount; ++i) {
   1046         const NumberFormat *nf = cache->getIntegerFormat();
   1047         if (i == measureCount - 1) {
   1048             nf = numberFormat->get();
   1049         }
   1050         if (fieldPositionFoundIndex == -1) {
   1051             formatMeasure(measures[i], *nf, results[i], fpos, status);
   1052             if (U_FAILURE(status)) {
   1053                 delete [] results;
   1054                 return appendTo;
   1055             }
   1056             if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) {
   1057                 fieldPositionFoundIndex = i;
   1058             }
   1059         } else {
   1060             formatMeasure(measures[i], *nf, results[i], dontCare, status);
   1061         }
   1062     }
   1063     int32_t offset;
   1064     listFormatter->format(
   1065             results,
   1066             measureCount,
   1067             appendTo,
   1068             fieldPositionFoundIndex,
   1069             offset,
   1070             status);
   1071     if (U_FAILURE(status)) {
   1072         delete [] results;
   1073         return appendTo;
   1074     }
   1075     if (offset != -1) {
   1076         pos.setBeginIndex(fpos.getBeginIndex() + offset);
   1077         pos.setEndIndex(fpos.getEndIndex() + offset);
   1078     }
   1079     delete [] results;
   1080     return appendTo;
   1081 }
   1082 
   1083 MeasureFormat* U_EXPORT2 MeasureFormat::createCurrencyFormat(const Locale& locale,
   1084                                                    UErrorCode& ec) {
   1085     CurrencyFormat* fmt = NULL;
   1086     if (U_SUCCESS(ec)) {
   1087         fmt = new CurrencyFormat(locale, ec);
   1088         if (U_FAILURE(ec)) {
   1089             delete fmt;
   1090             fmt = NULL;
   1091         }
   1092     }
   1093     return fmt;
   1094 }
   1095 
   1096 MeasureFormat* U_EXPORT2 MeasureFormat::createCurrencyFormat(UErrorCode& ec) {
   1097     if (U_FAILURE(ec)) {
   1098         return NULL;
   1099     }
   1100     return MeasureFormat::createCurrencyFormat(Locale::getDefault(), ec);
   1101 }
   1102 
   1103 U_NAMESPACE_END
   1104 
   1105 #endif /* #if !UCONFIG_NO_FORMATTING */
   1106