12e5b6d6dSopenharmony_ci// © 2016 and later: Unicode, Inc. and others. 22e5b6d6dSopenharmony_ci// License & terms of use: http://www.unicode.org/copyright.html 32e5b6d6dSopenharmony_ci/* 42e5b6d6dSopenharmony_ci********************************************************************** 52e5b6d6dSopenharmony_ci* Copyright (c) 2004-2016, International Business Machines 62e5b6d6dSopenharmony_ci* Corporation and others. All Rights Reserved. 72e5b6d6dSopenharmony_ci********************************************************************** 82e5b6d6dSopenharmony_ci* Author: Alan Liu 92e5b6d6dSopenharmony_ci* Created: April 20, 2004 102e5b6d6dSopenharmony_ci* Since: ICU 3.0 112e5b6d6dSopenharmony_ci********************************************************************** 122e5b6d6dSopenharmony_ci*/ 132e5b6d6dSopenharmony_ci#include "utypeinfo.h" // for 'typeid' to work 142e5b6d6dSopenharmony_ci#include "unicode/utypes.h" 152e5b6d6dSopenharmony_ci 162e5b6d6dSopenharmony_ci#if !UCONFIG_NO_FORMATTING 172e5b6d6dSopenharmony_ci 182e5b6d6dSopenharmony_ci#include "unicode/measfmt.h" 192e5b6d6dSopenharmony_ci#include "unicode/numfmt.h" 202e5b6d6dSopenharmony_ci#include "currfmt.h" 212e5b6d6dSopenharmony_ci#include "unicode/localpointer.h" 222e5b6d6dSopenharmony_ci#include "resource.h" 232e5b6d6dSopenharmony_ci#include "unicode/simpleformatter.h" 242e5b6d6dSopenharmony_ci#include "quantityformatter.h" 252e5b6d6dSopenharmony_ci#include "unicode/plurrule.h" 262e5b6d6dSopenharmony_ci#include "unicode/decimfmt.h" 272e5b6d6dSopenharmony_ci#include "uresimp.h" 282e5b6d6dSopenharmony_ci#include "unicode/ures.h" 292e5b6d6dSopenharmony_ci#include "unicode/ustring.h" 302e5b6d6dSopenharmony_ci#include "ureslocs.h" 312e5b6d6dSopenharmony_ci#include "cstring.h" 322e5b6d6dSopenharmony_ci#include "mutex.h" 332e5b6d6dSopenharmony_ci#include "ucln_in.h" 342e5b6d6dSopenharmony_ci#include "unicode/listformatter.h" 352e5b6d6dSopenharmony_ci#include "charstr.h" 362e5b6d6dSopenharmony_ci#include "unicode/putil.h" 372e5b6d6dSopenharmony_ci#include "unicode/smpdtfmt.h" 382e5b6d6dSopenharmony_ci#include "uassert.h" 392e5b6d6dSopenharmony_ci#include "unicode/numberformatter.h" 402e5b6d6dSopenharmony_ci#include "number_longnames.h" 412e5b6d6dSopenharmony_ci#include "number_utypes.h" 422e5b6d6dSopenharmony_ci 432e5b6d6dSopenharmony_ci#include "sharednumberformat.h" 442e5b6d6dSopenharmony_ci#include "sharedpluralrules.h" 452e5b6d6dSopenharmony_ci#include "standardplural.h" 462e5b6d6dSopenharmony_ci#include "unifiedcache.h" 472e5b6d6dSopenharmony_ci 482e5b6d6dSopenharmony_ci 492e5b6d6dSopenharmony_ciU_NAMESPACE_BEGIN 502e5b6d6dSopenharmony_ci 512e5b6d6dSopenharmony_ciusing number::impl::UFormattedNumberData; 522e5b6d6dSopenharmony_ci 532e5b6d6dSopenharmony_cistatic constexpr int32_t WIDTH_INDEX_COUNT = UMEASFMT_WIDTH_NARROW + 1; 542e5b6d6dSopenharmony_ci 552e5b6d6dSopenharmony_ciUOBJECT_DEFINE_RTTI_IMPLEMENTATION(MeasureFormat) 562e5b6d6dSopenharmony_ci 572e5b6d6dSopenharmony_ci// Used to format durations like 5:47 or 21:35:42. 582e5b6d6dSopenharmony_ciclass NumericDateFormatters : public UMemory { 592e5b6d6dSopenharmony_cipublic: 602e5b6d6dSopenharmony_ci // Formats like H:mm 612e5b6d6dSopenharmony_ci UnicodeString hourMinute; 622e5b6d6dSopenharmony_ci 632e5b6d6dSopenharmony_ci // formats like M:ss 642e5b6d6dSopenharmony_ci UnicodeString minuteSecond; 652e5b6d6dSopenharmony_ci 662e5b6d6dSopenharmony_ci // formats like H:mm:ss 672e5b6d6dSopenharmony_ci UnicodeString hourMinuteSecond; 682e5b6d6dSopenharmony_ci 692e5b6d6dSopenharmony_ci // Constructor that takes the actual patterns for hour-minute, 702e5b6d6dSopenharmony_ci // minute-second, and hour-minute-second respectively. 712e5b6d6dSopenharmony_ci NumericDateFormatters( 722e5b6d6dSopenharmony_ci const UnicodeString &hm, 732e5b6d6dSopenharmony_ci const UnicodeString &ms, 742e5b6d6dSopenharmony_ci const UnicodeString &hms) : 752e5b6d6dSopenharmony_ci hourMinute(hm), 762e5b6d6dSopenharmony_ci minuteSecond(ms), 772e5b6d6dSopenharmony_ci hourMinuteSecond(hms) { 782e5b6d6dSopenharmony_ci } 792e5b6d6dSopenharmony_ciprivate: 802e5b6d6dSopenharmony_ci NumericDateFormatters(const NumericDateFormatters &other); 812e5b6d6dSopenharmony_ci NumericDateFormatters &operator=(const NumericDateFormatters &other); 822e5b6d6dSopenharmony_ci}; 832e5b6d6dSopenharmony_ci 842e5b6d6dSopenharmony_cistatic UMeasureFormatWidth getRegularWidth(UMeasureFormatWidth width) { 852e5b6d6dSopenharmony_ci if (width >= WIDTH_INDEX_COUNT) { 862e5b6d6dSopenharmony_ci return UMEASFMT_WIDTH_NARROW; 872e5b6d6dSopenharmony_ci } 882e5b6d6dSopenharmony_ci return width; 892e5b6d6dSopenharmony_ci} 902e5b6d6dSopenharmony_ci 912e5b6d6dSopenharmony_cistatic UNumberUnitWidth getUnitWidth(UMeasureFormatWidth width) { 922e5b6d6dSopenharmony_ci switch (width) { 932e5b6d6dSopenharmony_ci case UMEASFMT_WIDTH_WIDE: 942e5b6d6dSopenharmony_ci return UNUM_UNIT_WIDTH_FULL_NAME; 952e5b6d6dSopenharmony_ci case UMEASFMT_WIDTH_NARROW: 962e5b6d6dSopenharmony_ci case UMEASFMT_WIDTH_NUMERIC: 972e5b6d6dSopenharmony_ci return UNUM_UNIT_WIDTH_NARROW; 982e5b6d6dSopenharmony_ci case UMEASFMT_WIDTH_SHORT: 992e5b6d6dSopenharmony_ci default: 1002e5b6d6dSopenharmony_ci return UNUM_UNIT_WIDTH_SHORT; 1012e5b6d6dSopenharmony_ci } 1022e5b6d6dSopenharmony_ci} 1032e5b6d6dSopenharmony_ci 1042e5b6d6dSopenharmony_ci/** 1052e5b6d6dSopenharmony_ci * Instances contain all MeasureFormat specific data for a particular locale. 1062e5b6d6dSopenharmony_ci * This data is cached. It is never copied, but is shared via shared pointers. 1072e5b6d6dSopenharmony_ci * 1082e5b6d6dSopenharmony_ci * Note: We might change the cache data to have an array[WIDTH_INDEX_COUNT] of 1092e5b6d6dSopenharmony_ci * complete sets of unit & per patterns, 1102e5b6d6dSopenharmony_ci * to correspond to the resource data and its aliases. 1112e5b6d6dSopenharmony_ci * 1122e5b6d6dSopenharmony_ci * TODO: Maybe store more sparsely in general, with pointers rather than potentially-empty objects. 1132e5b6d6dSopenharmony_ci */ 1142e5b6d6dSopenharmony_ciclass MeasureFormatCacheData : public SharedObject { 1152e5b6d6dSopenharmony_cipublic: 1162e5b6d6dSopenharmony_ci 1172e5b6d6dSopenharmony_ci /** 1182e5b6d6dSopenharmony_ci * Redirection data from root-bundle, top-level sideways aliases. 1192e5b6d6dSopenharmony_ci * - UMEASFMT_WIDTH_COUNT: initial value, just fall back to root 1202e5b6d6dSopenharmony_ci * - UMEASFMT_WIDTH_WIDE/SHORT/NARROW: sideways alias for missing data 1212e5b6d6dSopenharmony_ci */ 1222e5b6d6dSopenharmony_ci UMeasureFormatWidth widthFallback[WIDTH_INDEX_COUNT]; 1232e5b6d6dSopenharmony_ci 1242e5b6d6dSopenharmony_ci MeasureFormatCacheData(); 1252e5b6d6dSopenharmony_ci virtual ~MeasureFormatCacheData(); 1262e5b6d6dSopenharmony_ci 1272e5b6d6dSopenharmony_ci void adoptCurrencyFormat(int32_t widthIndex, NumberFormat *nfToAdopt) { 1282e5b6d6dSopenharmony_ci delete currencyFormats[widthIndex]; 1292e5b6d6dSopenharmony_ci currencyFormats[widthIndex] = nfToAdopt; 1302e5b6d6dSopenharmony_ci } 1312e5b6d6dSopenharmony_ci const NumberFormat *getCurrencyFormat(UMeasureFormatWidth width) const { 1322e5b6d6dSopenharmony_ci return currencyFormats[getRegularWidth(width)]; 1332e5b6d6dSopenharmony_ci } 1342e5b6d6dSopenharmony_ci void adoptIntegerFormat(NumberFormat *nfToAdopt) { 1352e5b6d6dSopenharmony_ci delete integerFormat; 1362e5b6d6dSopenharmony_ci integerFormat = nfToAdopt; 1372e5b6d6dSopenharmony_ci } 1382e5b6d6dSopenharmony_ci const NumberFormat *getIntegerFormat() const { 1392e5b6d6dSopenharmony_ci return integerFormat; 1402e5b6d6dSopenharmony_ci } 1412e5b6d6dSopenharmony_ci void adoptNumericDateFormatters(NumericDateFormatters *formattersToAdopt) { 1422e5b6d6dSopenharmony_ci delete numericDateFormatters; 1432e5b6d6dSopenharmony_ci numericDateFormatters = formattersToAdopt; 1442e5b6d6dSopenharmony_ci } 1452e5b6d6dSopenharmony_ci const NumericDateFormatters *getNumericDateFormatters() const { 1462e5b6d6dSopenharmony_ci return numericDateFormatters; 1472e5b6d6dSopenharmony_ci } 1482e5b6d6dSopenharmony_ci 1492e5b6d6dSopenharmony_ciprivate: 1502e5b6d6dSopenharmony_ci NumberFormat* currencyFormats[WIDTH_INDEX_COUNT]; 1512e5b6d6dSopenharmony_ci NumberFormat* integerFormat; 1522e5b6d6dSopenharmony_ci NumericDateFormatters* numericDateFormatters; 1532e5b6d6dSopenharmony_ci 1542e5b6d6dSopenharmony_ci MeasureFormatCacheData(const MeasureFormatCacheData &other); 1552e5b6d6dSopenharmony_ci MeasureFormatCacheData &operator=(const MeasureFormatCacheData &other); 1562e5b6d6dSopenharmony_ci}; 1572e5b6d6dSopenharmony_ci 1582e5b6d6dSopenharmony_ciMeasureFormatCacheData::MeasureFormatCacheData() 1592e5b6d6dSopenharmony_ci : integerFormat(nullptr), numericDateFormatters(nullptr) { 1602e5b6d6dSopenharmony_ci for (int32_t i = 0; i < WIDTH_INDEX_COUNT; ++i) { 1612e5b6d6dSopenharmony_ci widthFallback[i] = UMEASFMT_WIDTH_COUNT; 1622e5b6d6dSopenharmony_ci } 1632e5b6d6dSopenharmony_ci memset(currencyFormats, 0, sizeof(currencyFormats)); 1642e5b6d6dSopenharmony_ci} 1652e5b6d6dSopenharmony_ci 1662e5b6d6dSopenharmony_ciMeasureFormatCacheData::~MeasureFormatCacheData() { 1672e5b6d6dSopenharmony_ci for (int32_t i = 0; i < UPRV_LENGTHOF(currencyFormats); ++i) { 1682e5b6d6dSopenharmony_ci delete currencyFormats[i]; 1692e5b6d6dSopenharmony_ci } 1702e5b6d6dSopenharmony_ci // Note: the contents of 'dnams' are pointers into the resource bundle 1712e5b6d6dSopenharmony_ci delete integerFormat; 1722e5b6d6dSopenharmony_ci delete numericDateFormatters; 1732e5b6d6dSopenharmony_ci} 1742e5b6d6dSopenharmony_ci 1752e5b6d6dSopenharmony_cistatic UBool isCurrency(const MeasureUnit &unit) { 1762e5b6d6dSopenharmony_ci return (uprv_strcmp(unit.getType(), "currency") == 0); 1772e5b6d6dSopenharmony_ci} 1782e5b6d6dSopenharmony_ci 1792e5b6d6dSopenharmony_cistatic UBool getString( 1802e5b6d6dSopenharmony_ci const UResourceBundle *resource, 1812e5b6d6dSopenharmony_ci UnicodeString &result, 1822e5b6d6dSopenharmony_ci UErrorCode &status) { 1832e5b6d6dSopenharmony_ci int32_t len = 0; 1842e5b6d6dSopenharmony_ci const UChar *resStr = ures_getString(resource, &len, &status); 1852e5b6d6dSopenharmony_ci if (U_FAILURE(status)) { 1862e5b6d6dSopenharmony_ci return false; 1872e5b6d6dSopenharmony_ci } 1882e5b6d6dSopenharmony_ci result.setTo(true, resStr, len); 1892e5b6d6dSopenharmony_ci return true; 1902e5b6d6dSopenharmony_ci} 1912e5b6d6dSopenharmony_ci 1922e5b6d6dSopenharmony_cistatic UnicodeString loadNumericDateFormatterPattern( 1932e5b6d6dSopenharmony_ci const UResourceBundle *resource, 1942e5b6d6dSopenharmony_ci const char *pattern, 1952e5b6d6dSopenharmony_ci UErrorCode &status) { 1962e5b6d6dSopenharmony_ci UnicodeString result; 1972e5b6d6dSopenharmony_ci if (U_FAILURE(status)) { 1982e5b6d6dSopenharmony_ci return result; 1992e5b6d6dSopenharmony_ci } 2002e5b6d6dSopenharmony_ci CharString chs; 2012e5b6d6dSopenharmony_ci chs.append("durationUnits", status) 2022e5b6d6dSopenharmony_ci .append("/", status).append(pattern, status); 2032e5b6d6dSopenharmony_ci LocalUResourceBundlePointer patternBundle( 2042e5b6d6dSopenharmony_ci ures_getByKeyWithFallback( 2052e5b6d6dSopenharmony_ci resource, 2062e5b6d6dSopenharmony_ci chs.data(), 2072e5b6d6dSopenharmony_ci NULL, 2082e5b6d6dSopenharmony_ci &status)); 2092e5b6d6dSopenharmony_ci if (U_FAILURE(status)) { 2102e5b6d6dSopenharmony_ci return result; 2112e5b6d6dSopenharmony_ci } 2122e5b6d6dSopenharmony_ci getString(patternBundle.getAlias(), result, status); 2132e5b6d6dSopenharmony_ci // Replace 'h' with 'H' 2142e5b6d6dSopenharmony_ci int32_t len = result.length(); 2152e5b6d6dSopenharmony_ci UChar *buffer = result.getBuffer(len); 2162e5b6d6dSopenharmony_ci for (int32_t i = 0; i < len; ++i) { 2172e5b6d6dSopenharmony_ci if (buffer[i] == 0x68) { // 'h' 2182e5b6d6dSopenharmony_ci buffer[i] = 0x48; // 'H' 2192e5b6d6dSopenharmony_ci } 2202e5b6d6dSopenharmony_ci } 2212e5b6d6dSopenharmony_ci result.releaseBuffer(len); 2222e5b6d6dSopenharmony_ci return result; 2232e5b6d6dSopenharmony_ci} 2242e5b6d6dSopenharmony_ci 2252e5b6d6dSopenharmony_cistatic NumericDateFormatters *loadNumericDateFormatters( 2262e5b6d6dSopenharmony_ci const UResourceBundle *resource, 2272e5b6d6dSopenharmony_ci UErrorCode &status) { 2282e5b6d6dSopenharmony_ci if (U_FAILURE(status)) { 2292e5b6d6dSopenharmony_ci return NULL; 2302e5b6d6dSopenharmony_ci } 2312e5b6d6dSopenharmony_ci NumericDateFormatters *result = new NumericDateFormatters( 2322e5b6d6dSopenharmony_ci loadNumericDateFormatterPattern(resource, "hm", status), 2332e5b6d6dSopenharmony_ci loadNumericDateFormatterPattern(resource, "ms", status), 2342e5b6d6dSopenharmony_ci loadNumericDateFormatterPattern(resource, "hms", status)); 2352e5b6d6dSopenharmony_ci if (U_FAILURE(status)) { 2362e5b6d6dSopenharmony_ci delete result; 2372e5b6d6dSopenharmony_ci return NULL; 2382e5b6d6dSopenharmony_ci } 2392e5b6d6dSopenharmony_ci return result; 2402e5b6d6dSopenharmony_ci} 2412e5b6d6dSopenharmony_ci 2422e5b6d6dSopenharmony_citemplate<> 2432e5b6d6dSopenharmony_ciconst MeasureFormatCacheData *LocaleCacheKey<MeasureFormatCacheData>::createObject( 2442e5b6d6dSopenharmony_ci const void * /*unused*/, UErrorCode &status) const { 2452e5b6d6dSopenharmony_ci const char *localeId = fLoc.getName(); 2462e5b6d6dSopenharmony_ci LocalUResourceBundlePointer unitsBundle(ures_open(U_ICUDATA_UNIT, localeId, &status)); 2472e5b6d6dSopenharmony_ci static UNumberFormatStyle currencyStyles[] = { 2482e5b6d6dSopenharmony_ci UNUM_CURRENCY_PLURAL, UNUM_CURRENCY_ISO, UNUM_CURRENCY}; 2492e5b6d6dSopenharmony_ci LocalPointer<MeasureFormatCacheData> result(new MeasureFormatCacheData(), status); 2502e5b6d6dSopenharmony_ci if (U_FAILURE(status)) { 2512e5b6d6dSopenharmony_ci return NULL; 2522e5b6d6dSopenharmony_ci } 2532e5b6d6dSopenharmony_ci result->adoptNumericDateFormatters(loadNumericDateFormatters( 2542e5b6d6dSopenharmony_ci unitsBundle.getAlias(), status)); 2552e5b6d6dSopenharmony_ci if (U_FAILURE(status)) { 2562e5b6d6dSopenharmony_ci return NULL; 2572e5b6d6dSopenharmony_ci } 2582e5b6d6dSopenharmony_ci 2592e5b6d6dSopenharmony_ci for (int32_t i = 0; i < WIDTH_INDEX_COUNT; ++i) { 2602e5b6d6dSopenharmony_ci // NumberFormat::createInstance can erase warning codes from status, so pass it 2612e5b6d6dSopenharmony_ci // a separate status instance 2622e5b6d6dSopenharmony_ci UErrorCode localStatus = U_ZERO_ERROR; 2632e5b6d6dSopenharmony_ci result->adoptCurrencyFormat(i, NumberFormat::createInstance( 2642e5b6d6dSopenharmony_ci localeId, currencyStyles[i], localStatus)); 2652e5b6d6dSopenharmony_ci if (localStatus != U_ZERO_ERROR) { 2662e5b6d6dSopenharmony_ci status = localStatus; 2672e5b6d6dSopenharmony_ci } 2682e5b6d6dSopenharmony_ci if (U_FAILURE(status)) { 2692e5b6d6dSopenharmony_ci return NULL; 2702e5b6d6dSopenharmony_ci } 2712e5b6d6dSopenharmony_ci } 2722e5b6d6dSopenharmony_ci NumberFormat *inf = NumberFormat::createInstance( 2732e5b6d6dSopenharmony_ci localeId, UNUM_DECIMAL, status); 2742e5b6d6dSopenharmony_ci if (U_FAILURE(status)) { 2752e5b6d6dSopenharmony_ci return NULL; 2762e5b6d6dSopenharmony_ci } 2772e5b6d6dSopenharmony_ci inf->setMaximumFractionDigits(0); 2782e5b6d6dSopenharmony_ci DecimalFormat *decfmt = dynamic_cast<DecimalFormat *>(inf); 2792e5b6d6dSopenharmony_ci if (decfmt != NULL) { 2802e5b6d6dSopenharmony_ci decfmt->setRoundingMode(DecimalFormat::kRoundDown); 2812e5b6d6dSopenharmony_ci } 2822e5b6d6dSopenharmony_ci result->adoptIntegerFormat(inf); 2832e5b6d6dSopenharmony_ci result->addRef(); 2842e5b6d6dSopenharmony_ci return result.orphan(); 2852e5b6d6dSopenharmony_ci} 2862e5b6d6dSopenharmony_ci 2872e5b6d6dSopenharmony_cistatic UBool isTimeUnit(const MeasureUnit &mu, const char *tu) { 2882e5b6d6dSopenharmony_ci return uprv_strcmp(mu.getType(), "duration") == 0 && 2892e5b6d6dSopenharmony_ci uprv_strcmp(mu.getSubtype(), tu) == 0; 2902e5b6d6dSopenharmony_ci} 2912e5b6d6dSopenharmony_ci 2922e5b6d6dSopenharmony_ci// Converts a composite measure into hours-minutes-seconds and stores at hms 2932e5b6d6dSopenharmony_ci// array. [0] is hours; [1] is minutes; [2] is seconds. Returns a bit map of 2942e5b6d6dSopenharmony_ci// units found: 1=hours, 2=minutes, 4=seconds. For example, if measures 2952e5b6d6dSopenharmony_ci// contains hours-minutes, this function would return 3. 2962e5b6d6dSopenharmony_ci// 2972e5b6d6dSopenharmony_ci// If measures cannot be converted into hours, minutes, seconds or if amounts 2982e5b6d6dSopenharmony_ci// are negative, or if hours, minutes, seconds are out of order, returns 0. 2992e5b6d6dSopenharmony_cistatic int32_t toHMS( 3002e5b6d6dSopenharmony_ci const Measure *measures, 3012e5b6d6dSopenharmony_ci int32_t measureCount, 3022e5b6d6dSopenharmony_ci Formattable *hms, 3032e5b6d6dSopenharmony_ci UErrorCode &status) { 3042e5b6d6dSopenharmony_ci if (U_FAILURE(status)) { 3052e5b6d6dSopenharmony_ci return 0; 3062e5b6d6dSopenharmony_ci } 3072e5b6d6dSopenharmony_ci int32_t result = 0; 3082e5b6d6dSopenharmony_ci if (U_FAILURE(status)) { 3092e5b6d6dSopenharmony_ci return 0; 3102e5b6d6dSopenharmony_ci } 3112e5b6d6dSopenharmony_ci // We use copy constructor to ensure that both sides of equality operator 3122e5b6d6dSopenharmony_ci // are instances of MeasureUnit base class and not a subclass. Otherwise, 3132e5b6d6dSopenharmony_ci // operator== will immediately return false. 3142e5b6d6dSopenharmony_ci for (int32_t i = 0; i < measureCount; ++i) { 3152e5b6d6dSopenharmony_ci if (isTimeUnit(measures[i].getUnit(), "hour")) { 3162e5b6d6dSopenharmony_ci // hour must come first 3172e5b6d6dSopenharmony_ci if (result >= 1) { 3182e5b6d6dSopenharmony_ci return 0; 3192e5b6d6dSopenharmony_ci } 3202e5b6d6dSopenharmony_ci hms[0] = measures[i].getNumber(); 3212e5b6d6dSopenharmony_ci if (hms[0].getDouble() < 0.0) { 3222e5b6d6dSopenharmony_ci return 0; 3232e5b6d6dSopenharmony_ci } 3242e5b6d6dSopenharmony_ci result |= 1; 3252e5b6d6dSopenharmony_ci } else if (isTimeUnit(measures[i].getUnit(), "minute")) { 3262e5b6d6dSopenharmony_ci // minute must come after hour 3272e5b6d6dSopenharmony_ci if (result >= 2) { 3282e5b6d6dSopenharmony_ci return 0; 3292e5b6d6dSopenharmony_ci } 3302e5b6d6dSopenharmony_ci hms[1] = measures[i].getNumber(); 3312e5b6d6dSopenharmony_ci if (hms[1].getDouble() < 0.0) { 3322e5b6d6dSopenharmony_ci return 0; 3332e5b6d6dSopenharmony_ci } 3342e5b6d6dSopenharmony_ci result |= 2; 3352e5b6d6dSopenharmony_ci } else if (isTimeUnit(measures[i].getUnit(), "second")) { 3362e5b6d6dSopenharmony_ci // second must come after hour and minute 3372e5b6d6dSopenharmony_ci if (result >= 4) { 3382e5b6d6dSopenharmony_ci return 0; 3392e5b6d6dSopenharmony_ci } 3402e5b6d6dSopenharmony_ci hms[2] = measures[i].getNumber(); 3412e5b6d6dSopenharmony_ci if (hms[2].getDouble() < 0.0) { 3422e5b6d6dSopenharmony_ci return 0; 3432e5b6d6dSopenharmony_ci } 3442e5b6d6dSopenharmony_ci result |= 4; 3452e5b6d6dSopenharmony_ci } else { 3462e5b6d6dSopenharmony_ci return 0; 3472e5b6d6dSopenharmony_ci } 3482e5b6d6dSopenharmony_ci } 3492e5b6d6dSopenharmony_ci return result; 3502e5b6d6dSopenharmony_ci} 3512e5b6d6dSopenharmony_ci 3522e5b6d6dSopenharmony_ci 3532e5b6d6dSopenharmony_ciMeasureFormat::MeasureFormat( 3542e5b6d6dSopenharmony_ci const Locale &locale, UMeasureFormatWidth w, UErrorCode &status) 3552e5b6d6dSopenharmony_ci : cache(NULL), 3562e5b6d6dSopenharmony_ci numberFormat(NULL), 3572e5b6d6dSopenharmony_ci pluralRules(NULL), 3582e5b6d6dSopenharmony_ci fWidth(w), 3592e5b6d6dSopenharmony_ci listFormatter(NULL) { 3602e5b6d6dSopenharmony_ci initMeasureFormat(locale, w, NULL, status); 3612e5b6d6dSopenharmony_ci} 3622e5b6d6dSopenharmony_ci 3632e5b6d6dSopenharmony_ciMeasureFormat::MeasureFormat( 3642e5b6d6dSopenharmony_ci const Locale &locale, 3652e5b6d6dSopenharmony_ci UMeasureFormatWidth w, 3662e5b6d6dSopenharmony_ci NumberFormat *nfToAdopt, 3672e5b6d6dSopenharmony_ci UErrorCode &status) 3682e5b6d6dSopenharmony_ci : cache(NULL), 3692e5b6d6dSopenharmony_ci numberFormat(NULL), 3702e5b6d6dSopenharmony_ci pluralRules(NULL), 3712e5b6d6dSopenharmony_ci fWidth(w), 3722e5b6d6dSopenharmony_ci listFormatter(NULL) { 3732e5b6d6dSopenharmony_ci initMeasureFormat(locale, w, nfToAdopt, status); 3742e5b6d6dSopenharmony_ci} 3752e5b6d6dSopenharmony_ci 3762e5b6d6dSopenharmony_ciMeasureFormat::MeasureFormat(const MeasureFormat &other) : 3772e5b6d6dSopenharmony_ci Format(other), 3782e5b6d6dSopenharmony_ci cache(other.cache), 3792e5b6d6dSopenharmony_ci numberFormat(other.numberFormat), 3802e5b6d6dSopenharmony_ci pluralRules(other.pluralRules), 3812e5b6d6dSopenharmony_ci fWidth(other.fWidth), 3822e5b6d6dSopenharmony_ci listFormatter(NULL) { 3832e5b6d6dSopenharmony_ci cache->addRef(); 3842e5b6d6dSopenharmony_ci numberFormat->addRef(); 3852e5b6d6dSopenharmony_ci pluralRules->addRef(); 3862e5b6d6dSopenharmony_ci if (other.listFormatter != NULL) { 3872e5b6d6dSopenharmony_ci listFormatter = new ListFormatter(*other.listFormatter); 3882e5b6d6dSopenharmony_ci } 3892e5b6d6dSopenharmony_ci} 3902e5b6d6dSopenharmony_ci 3912e5b6d6dSopenharmony_ciMeasureFormat &MeasureFormat::operator=(const MeasureFormat &other) { 3922e5b6d6dSopenharmony_ci if (this == &other) { 3932e5b6d6dSopenharmony_ci return *this; 3942e5b6d6dSopenharmony_ci } 3952e5b6d6dSopenharmony_ci Format::operator=(other); 3962e5b6d6dSopenharmony_ci SharedObject::copyPtr(other.cache, cache); 3972e5b6d6dSopenharmony_ci SharedObject::copyPtr(other.numberFormat, numberFormat); 3982e5b6d6dSopenharmony_ci SharedObject::copyPtr(other.pluralRules, pluralRules); 3992e5b6d6dSopenharmony_ci fWidth = other.fWidth; 4002e5b6d6dSopenharmony_ci delete listFormatter; 4012e5b6d6dSopenharmony_ci if (other.listFormatter != NULL) { 4022e5b6d6dSopenharmony_ci listFormatter = new ListFormatter(*other.listFormatter); 4032e5b6d6dSopenharmony_ci } else { 4042e5b6d6dSopenharmony_ci listFormatter = NULL; 4052e5b6d6dSopenharmony_ci } 4062e5b6d6dSopenharmony_ci return *this; 4072e5b6d6dSopenharmony_ci} 4082e5b6d6dSopenharmony_ci 4092e5b6d6dSopenharmony_ciMeasureFormat::MeasureFormat() : 4102e5b6d6dSopenharmony_ci cache(NULL), 4112e5b6d6dSopenharmony_ci numberFormat(NULL), 4122e5b6d6dSopenharmony_ci pluralRules(NULL), 4132e5b6d6dSopenharmony_ci fWidth(UMEASFMT_WIDTH_SHORT), 4142e5b6d6dSopenharmony_ci listFormatter(NULL) { 4152e5b6d6dSopenharmony_ci} 4162e5b6d6dSopenharmony_ci 4172e5b6d6dSopenharmony_ciMeasureFormat::~MeasureFormat() { 4182e5b6d6dSopenharmony_ci if (cache != NULL) { 4192e5b6d6dSopenharmony_ci cache->removeRef(); 4202e5b6d6dSopenharmony_ci } 4212e5b6d6dSopenharmony_ci if (numberFormat != NULL) { 4222e5b6d6dSopenharmony_ci numberFormat->removeRef(); 4232e5b6d6dSopenharmony_ci } 4242e5b6d6dSopenharmony_ci if (pluralRules != NULL) { 4252e5b6d6dSopenharmony_ci pluralRules->removeRef(); 4262e5b6d6dSopenharmony_ci } 4272e5b6d6dSopenharmony_ci delete listFormatter; 4282e5b6d6dSopenharmony_ci} 4292e5b6d6dSopenharmony_ci 4302e5b6d6dSopenharmony_cibool MeasureFormat::operator==(const Format &other) const { 4312e5b6d6dSopenharmony_ci if (this == &other) { // Same object, equal 4322e5b6d6dSopenharmony_ci return true; 4332e5b6d6dSopenharmony_ci } 4342e5b6d6dSopenharmony_ci if (!Format::operator==(other)) { 4352e5b6d6dSopenharmony_ci return false; 4362e5b6d6dSopenharmony_ci } 4372e5b6d6dSopenharmony_ci const MeasureFormat &rhs = static_cast<const MeasureFormat &>(other); 4382e5b6d6dSopenharmony_ci 4392e5b6d6dSopenharmony_ci // Note: Since the ListFormatter depends only on Locale and width, we 4402e5b6d6dSopenharmony_ci // don't have to check it here. 4412e5b6d6dSopenharmony_ci 4422e5b6d6dSopenharmony_ci // differing widths aren't equivalent 4432e5b6d6dSopenharmony_ci if (fWidth != rhs.fWidth) { 4442e5b6d6dSopenharmony_ci return false; 4452e5b6d6dSopenharmony_ci } 4462e5b6d6dSopenharmony_ci // Width the same check locales. 4472e5b6d6dSopenharmony_ci // We don't need to check locales if both objects have same cache. 4482e5b6d6dSopenharmony_ci if (cache != rhs.cache) { 4492e5b6d6dSopenharmony_ci UErrorCode status = U_ZERO_ERROR; 4502e5b6d6dSopenharmony_ci const char *localeId = getLocaleID(status); 4512e5b6d6dSopenharmony_ci const char *rhsLocaleId = rhs.getLocaleID(status); 4522e5b6d6dSopenharmony_ci if (U_FAILURE(status)) { 4532e5b6d6dSopenharmony_ci // On failure, assume not equal 4542e5b6d6dSopenharmony_ci return false; 4552e5b6d6dSopenharmony_ci } 4562e5b6d6dSopenharmony_ci if (uprv_strcmp(localeId, rhsLocaleId) != 0) { 4572e5b6d6dSopenharmony_ci return false; 4582e5b6d6dSopenharmony_ci } 4592e5b6d6dSopenharmony_ci } 4602e5b6d6dSopenharmony_ci // Locales same, check NumberFormat if shared data differs. 4612e5b6d6dSopenharmony_ci return ( 4622e5b6d6dSopenharmony_ci numberFormat == rhs.numberFormat || 4632e5b6d6dSopenharmony_ci **numberFormat == **rhs.numberFormat); 4642e5b6d6dSopenharmony_ci} 4652e5b6d6dSopenharmony_ci 4662e5b6d6dSopenharmony_ciMeasureFormat *MeasureFormat::clone() const { 4672e5b6d6dSopenharmony_ci return new MeasureFormat(*this); 4682e5b6d6dSopenharmony_ci} 4692e5b6d6dSopenharmony_ci 4702e5b6d6dSopenharmony_ciUnicodeString &MeasureFormat::format( 4712e5b6d6dSopenharmony_ci const Formattable &obj, 4722e5b6d6dSopenharmony_ci UnicodeString &appendTo, 4732e5b6d6dSopenharmony_ci FieldPosition &pos, 4742e5b6d6dSopenharmony_ci UErrorCode &status) const { 4752e5b6d6dSopenharmony_ci if (U_FAILURE(status)) return appendTo; 4762e5b6d6dSopenharmony_ci if (obj.getType() == Formattable::kObject) { 4772e5b6d6dSopenharmony_ci const UObject* formatObj = obj.getObject(); 4782e5b6d6dSopenharmony_ci const Measure* amount = dynamic_cast<const Measure*>(formatObj); 4792e5b6d6dSopenharmony_ci if (amount != NULL) { 4802e5b6d6dSopenharmony_ci return formatMeasure( 4812e5b6d6dSopenharmony_ci *amount, **numberFormat, appendTo, pos, status); 4822e5b6d6dSopenharmony_ci } 4832e5b6d6dSopenharmony_ci } 4842e5b6d6dSopenharmony_ci status = U_ILLEGAL_ARGUMENT_ERROR; 4852e5b6d6dSopenharmony_ci return appendTo; 4862e5b6d6dSopenharmony_ci} 4872e5b6d6dSopenharmony_ci 4882e5b6d6dSopenharmony_civoid MeasureFormat::parseObject( 4892e5b6d6dSopenharmony_ci const UnicodeString & /*source*/, 4902e5b6d6dSopenharmony_ci Formattable & /*result*/, 4912e5b6d6dSopenharmony_ci ParsePosition& /*pos*/) const { 4922e5b6d6dSopenharmony_ci return; 4932e5b6d6dSopenharmony_ci} 4942e5b6d6dSopenharmony_ci 4952e5b6d6dSopenharmony_ciUnicodeString &MeasureFormat::formatMeasurePerUnit( 4962e5b6d6dSopenharmony_ci const Measure &measure, 4972e5b6d6dSopenharmony_ci const MeasureUnit &perUnit, 4982e5b6d6dSopenharmony_ci UnicodeString &appendTo, 4992e5b6d6dSopenharmony_ci FieldPosition &pos, 5002e5b6d6dSopenharmony_ci UErrorCode &status) const { 5012e5b6d6dSopenharmony_ci if (U_FAILURE(status)) { 5022e5b6d6dSopenharmony_ci return appendTo; 5032e5b6d6dSopenharmony_ci } 5042e5b6d6dSopenharmony_ci auto* df = dynamic_cast<const DecimalFormat*>(&getNumberFormatInternal()); 5052e5b6d6dSopenharmony_ci if (df == nullptr) { 5062e5b6d6dSopenharmony_ci // Don't know how to handle other types of NumberFormat 5072e5b6d6dSopenharmony_ci status = U_UNSUPPORTED_ERROR; 5082e5b6d6dSopenharmony_ci return appendTo; 5092e5b6d6dSopenharmony_ci } 5102e5b6d6dSopenharmony_ci UFormattedNumberData result; 5112e5b6d6dSopenharmony_ci if (auto* lnf = df->toNumberFormatter(status)) { 5122e5b6d6dSopenharmony_ci result.quantity.setToDouble(measure.getNumber().getDouble(status)); 5132e5b6d6dSopenharmony_ci lnf->unit(measure.getUnit()) 5142e5b6d6dSopenharmony_ci .perUnit(perUnit) 5152e5b6d6dSopenharmony_ci .unitWidth(getUnitWidth(fWidth)) 5162e5b6d6dSopenharmony_ci .formatImpl(&result, status); 5172e5b6d6dSopenharmony_ci } 5182e5b6d6dSopenharmony_ci DecimalFormat::fieldPositionHelper(result, pos, appendTo.length(), status); 5192e5b6d6dSopenharmony_ci appendTo.append(result.toTempString(status)); 5202e5b6d6dSopenharmony_ci return appendTo; 5212e5b6d6dSopenharmony_ci} 5222e5b6d6dSopenharmony_ci 5232e5b6d6dSopenharmony_ciUnicodeString &MeasureFormat::formatMeasures( 5242e5b6d6dSopenharmony_ci const Measure *measures, 5252e5b6d6dSopenharmony_ci int32_t measureCount, 5262e5b6d6dSopenharmony_ci UnicodeString &appendTo, 5272e5b6d6dSopenharmony_ci FieldPosition &pos, 5282e5b6d6dSopenharmony_ci UErrorCode &status) const { 5292e5b6d6dSopenharmony_ci if (U_FAILURE(status)) { 5302e5b6d6dSopenharmony_ci return appendTo; 5312e5b6d6dSopenharmony_ci } 5322e5b6d6dSopenharmony_ci if (measureCount == 0) { 5332e5b6d6dSopenharmony_ci return appendTo; 5342e5b6d6dSopenharmony_ci } 5352e5b6d6dSopenharmony_ci if (measureCount == 1) { 5362e5b6d6dSopenharmony_ci return formatMeasure(measures[0], **numberFormat, appendTo, pos, status); 5372e5b6d6dSopenharmony_ci } 5382e5b6d6dSopenharmony_ci if (fWidth == UMEASFMT_WIDTH_NUMERIC) { 5392e5b6d6dSopenharmony_ci Formattable hms[3]; 5402e5b6d6dSopenharmony_ci int32_t bitMap = toHMS(measures, measureCount, hms, status); 5412e5b6d6dSopenharmony_ci if (bitMap > 0) { 5422e5b6d6dSopenharmony_ci return formatNumeric(hms, bitMap, appendTo, status); 5432e5b6d6dSopenharmony_ci } 5442e5b6d6dSopenharmony_ci } 5452e5b6d6dSopenharmony_ci if (pos.getField() != FieldPosition::DONT_CARE) { 5462e5b6d6dSopenharmony_ci return formatMeasuresSlowTrack( 5472e5b6d6dSopenharmony_ci measures, measureCount, appendTo, pos, status); 5482e5b6d6dSopenharmony_ci } 5492e5b6d6dSopenharmony_ci UnicodeString *results = new UnicodeString[measureCount]; 5502e5b6d6dSopenharmony_ci if (results == NULL) { 5512e5b6d6dSopenharmony_ci status = U_MEMORY_ALLOCATION_ERROR; 5522e5b6d6dSopenharmony_ci return appendTo; 5532e5b6d6dSopenharmony_ci } 5542e5b6d6dSopenharmony_ci for (int32_t i = 0; i < measureCount; ++i) { 5552e5b6d6dSopenharmony_ci const NumberFormat *nf = cache->getIntegerFormat(); 5562e5b6d6dSopenharmony_ci if (i == measureCount - 1) { 5572e5b6d6dSopenharmony_ci nf = numberFormat->get(); 5582e5b6d6dSopenharmony_ci } 5592e5b6d6dSopenharmony_ci formatMeasure( 5602e5b6d6dSopenharmony_ci measures[i], 5612e5b6d6dSopenharmony_ci *nf, 5622e5b6d6dSopenharmony_ci results[i], 5632e5b6d6dSopenharmony_ci pos, 5642e5b6d6dSopenharmony_ci status); 5652e5b6d6dSopenharmony_ci } 5662e5b6d6dSopenharmony_ci listFormatter->format(results, measureCount, appendTo, status); 5672e5b6d6dSopenharmony_ci delete [] results; 5682e5b6d6dSopenharmony_ci return appendTo; 5692e5b6d6dSopenharmony_ci} 5702e5b6d6dSopenharmony_ci 5712e5b6d6dSopenharmony_ciUnicodeString MeasureFormat::getUnitDisplayName(const MeasureUnit& unit, UErrorCode& status) const { 5722e5b6d6dSopenharmony_ci return number::impl::LongNameHandler::getUnitDisplayName( 5732e5b6d6dSopenharmony_ci getLocale(status), 5742e5b6d6dSopenharmony_ci unit, 5752e5b6d6dSopenharmony_ci getUnitWidth(fWidth), 5762e5b6d6dSopenharmony_ci status); 5772e5b6d6dSopenharmony_ci} 5782e5b6d6dSopenharmony_ci 5792e5b6d6dSopenharmony_civoid MeasureFormat::initMeasureFormat( 5802e5b6d6dSopenharmony_ci const Locale &locale, 5812e5b6d6dSopenharmony_ci UMeasureFormatWidth w, 5822e5b6d6dSopenharmony_ci NumberFormat *nfToAdopt, 5832e5b6d6dSopenharmony_ci UErrorCode &status) { 5842e5b6d6dSopenharmony_ci static const UListFormatterWidth listWidths[] = { 5852e5b6d6dSopenharmony_ci ULISTFMT_WIDTH_WIDE, 5862e5b6d6dSopenharmony_ci ULISTFMT_WIDTH_SHORT, 5872e5b6d6dSopenharmony_ci ULISTFMT_WIDTH_NARROW}; 5882e5b6d6dSopenharmony_ci LocalPointer<NumberFormat> nf(nfToAdopt); 5892e5b6d6dSopenharmony_ci if (U_FAILURE(status)) { 5902e5b6d6dSopenharmony_ci return; 5912e5b6d6dSopenharmony_ci } 5922e5b6d6dSopenharmony_ci const char *name = locale.getName(); 5932e5b6d6dSopenharmony_ci setLocaleIDs(name, name); 5942e5b6d6dSopenharmony_ci 5952e5b6d6dSopenharmony_ci UnifiedCache::getByLocale(locale, cache, status); 5962e5b6d6dSopenharmony_ci if (U_FAILURE(status)) { 5972e5b6d6dSopenharmony_ci return; 5982e5b6d6dSopenharmony_ci } 5992e5b6d6dSopenharmony_ci 6002e5b6d6dSopenharmony_ci const SharedPluralRules *pr = PluralRules::createSharedInstance( 6012e5b6d6dSopenharmony_ci locale, UPLURAL_TYPE_CARDINAL, status); 6022e5b6d6dSopenharmony_ci if (U_FAILURE(status)) { 6032e5b6d6dSopenharmony_ci return; 6042e5b6d6dSopenharmony_ci } 6052e5b6d6dSopenharmony_ci SharedObject::copyPtr(pr, pluralRules); 6062e5b6d6dSopenharmony_ci pr->removeRef(); 6072e5b6d6dSopenharmony_ci if (nf.isNull()) { 6082e5b6d6dSopenharmony_ci // TODO: Clean this up 6092e5b6d6dSopenharmony_ci const SharedNumberFormat *shared = NumberFormat::createSharedInstance( 6102e5b6d6dSopenharmony_ci locale, UNUM_DECIMAL, status); 6112e5b6d6dSopenharmony_ci if (U_FAILURE(status)) { 6122e5b6d6dSopenharmony_ci return; 6132e5b6d6dSopenharmony_ci } 6142e5b6d6dSopenharmony_ci SharedObject::copyPtr(shared, numberFormat); 6152e5b6d6dSopenharmony_ci shared->removeRef(); 6162e5b6d6dSopenharmony_ci } else { 6172e5b6d6dSopenharmony_ci adoptNumberFormat(nf.orphan(), status); 6182e5b6d6dSopenharmony_ci if (U_FAILURE(status)) { 6192e5b6d6dSopenharmony_ci return; 6202e5b6d6dSopenharmony_ci } 6212e5b6d6dSopenharmony_ci } 6222e5b6d6dSopenharmony_ci fWidth = w; 6232e5b6d6dSopenharmony_ci delete listFormatter; 6242e5b6d6dSopenharmony_ci listFormatter = ListFormatter::createInstance( 6252e5b6d6dSopenharmony_ci locale, 6262e5b6d6dSopenharmony_ci ULISTFMT_TYPE_UNITS, 6272e5b6d6dSopenharmony_ci listWidths[getRegularWidth(fWidth)], 6282e5b6d6dSopenharmony_ci status); 6292e5b6d6dSopenharmony_ci} 6302e5b6d6dSopenharmony_ci 6312e5b6d6dSopenharmony_civoid MeasureFormat::adoptNumberFormat( 6322e5b6d6dSopenharmony_ci NumberFormat *nfToAdopt, UErrorCode &status) { 6332e5b6d6dSopenharmony_ci LocalPointer<NumberFormat> nf(nfToAdopt); 6342e5b6d6dSopenharmony_ci if (U_FAILURE(status)) { 6352e5b6d6dSopenharmony_ci return; 6362e5b6d6dSopenharmony_ci } 6372e5b6d6dSopenharmony_ci SharedNumberFormat *shared = new SharedNumberFormat(nf.getAlias()); 6382e5b6d6dSopenharmony_ci if (shared == NULL) { 6392e5b6d6dSopenharmony_ci status = U_MEMORY_ALLOCATION_ERROR; 6402e5b6d6dSopenharmony_ci return; 6412e5b6d6dSopenharmony_ci } 6422e5b6d6dSopenharmony_ci nf.orphan(); 6432e5b6d6dSopenharmony_ci SharedObject::copyPtr(shared, numberFormat); 6442e5b6d6dSopenharmony_ci} 6452e5b6d6dSopenharmony_ci 6462e5b6d6dSopenharmony_ciUBool MeasureFormat::setMeasureFormatLocale(const Locale &locale, UErrorCode &status) { 6472e5b6d6dSopenharmony_ci if (U_FAILURE(status) || locale == getLocale(status)) { 6482e5b6d6dSopenharmony_ci return false; 6492e5b6d6dSopenharmony_ci } 6502e5b6d6dSopenharmony_ci initMeasureFormat(locale, fWidth, NULL, status); 6512e5b6d6dSopenharmony_ci return U_SUCCESS(status); 6522e5b6d6dSopenharmony_ci} 6532e5b6d6dSopenharmony_ci 6542e5b6d6dSopenharmony_ciconst NumberFormat &MeasureFormat::getNumberFormatInternal() const { 6552e5b6d6dSopenharmony_ci return **numberFormat; 6562e5b6d6dSopenharmony_ci} 6572e5b6d6dSopenharmony_ci 6582e5b6d6dSopenharmony_ciconst NumberFormat &MeasureFormat::getCurrencyFormatInternal() const { 6592e5b6d6dSopenharmony_ci return *cache->getCurrencyFormat(UMEASFMT_WIDTH_NARROW); 6602e5b6d6dSopenharmony_ci} 6612e5b6d6dSopenharmony_ci 6622e5b6d6dSopenharmony_ciconst PluralRules &MeasureFormat::getPluralRules() const { 6632e5b6d6dSopenharmony_ci return **pluralRules; 6642e5b6d6dSopenharmony_ci} 6652e5b6d6dSopenharmony_ci 6662e5b6d6dSopenharmony_ciLocale MeasureFormat::getLocale(UErrorCode &status) const { 6672e5b6d6dSopenharmony_ci return Format::getLocale(ULOC_VALID_LOCALE, status); 6682e5b6d6dSopenharmony_ci} 6692e5b6d6dSopenharmony_ci 6702e5b6d6dSopenharmony_ciconst char *MeasureFormat::getLocaleID(UErrorCode &status) const { 6712e5b6d6dSopenharmony_ci return Format::getLocaleID(ULOC_VALID_LOCALE, status); 6722e5b6d6dSopenharmony_ci} 6732e5b6d6dSopenharmony_ci 6742e5b6d6dSopenharmony_ciUnicodeString &MeasureFormat::formatMeasure( 6752e5b6d6dSopenharmony_ci const Measure &measure, 6762e5b6d6dSopenharmony_ci const NumberFormat &nf, 6772e5b6d6dSopenharmony_ci UnicodeString &appendTo, 6782e5b6d6dSopenharmony_ci FieldPosition &pos, 6792e5b6d6dSopenharmony_ci UErrorCode &status) const { 6802e5b6d6dSopenharmony_ci if (U_FAILURE(status)) { 6812e5b6d6dSopenharmony_ci return appendTo; 6822e5b6d6dSopenharmony_ci } 6832e5b6d6dSopenharmony_ci const Formattable& amtNumber = measure.getNumber(); 6842e5b6d6dSopenharmony_ci const MeasureUnit& amtUnit = measure.getUnit(); 6852e5b6d6dSopenharmony_ci if (isCurrency(amtUnit)) { 6862e5b6d6dSopenharmony_ci UChar isoCode[4]; 6872e5b6d6dSopenharmony_ci u_charsToUChars(amtUnit.getSubtype(), isoCode, 4); 6882e5b6d6dSopenharmony_ci return cache->getCurrencyFormat(fWidth)->format( 6892e5b6d6dSopenharmony_ci new CurrencyAmount(amtNumber, isoCode, status), 6902e5b6d6dSopenharmony_ci appendTo, 6912e5b6d6dSopenharmony_ci pos, 6922e5b6d6dSopenharmony_ci status); 6932e5b6d6dSopenharmony_ci } 6942e5b6d6dSopenharmony_ci auto* df = dynamic_cast<const DecimalFormat*>(&nf); 6952e5b6d6dSopenharmony_ci if (df == nullptr) { 6962e5b6d6dSopenharmony_ci // Handle other types of NumberFormat using the ICU 63 code, modified to 6972e5b6d6dSopenharmony_ci // get the unitPattern from LongNameHandler and handle fallback to OTHER. 6982e5b6d6dSopenharmony_ci UnicodeString formattedNumber; 6992e5b6d6dSopenharmony_ci StandardPlural::Form pluralForm = QuantityFormatter::selectPlural( 7002e5b6d6dSopenharmony_ci amtNumber, nf, **pluralRules, formattedNumber, pos, status); 7012e5b6d6dSopenharmony_ci UnicodeString pattern = number::impl::LongNameHandler::getUnitPattern(getLocale(status), 7022e5b6d6dSopenharmony_ci amtUnit, getUnitWidth(fWidth), pluralForm, status); 7032e5b6d6dSopenharmony_ci // The above handles fallback from other widths to short, and from other plural forms to OTHER 7042e5b6d6dSopenharmony_ci if (U_FAILURE(status)) { 7052e5b6d6dSopenharmony_ci return appendTo; 7062e5b6d6dSopenharmony_ci } 7072e5b6d6dSopenharmony_ci SimpleFormatter formatter(pattern, 0, 1, status); 7082e5b6d6dSopenharmony_ci return QuantityFormatter::format(formatter, formattedNumber, appendTo, pos, status); 7092e5b6d6dSopenharmony_ci } 7102e5b6d6dSopenharmony_ci UFormattedNumberData result; 7112e5b6d6dSopenharmony_ci if (auto* lnf = df->toNumberFormatter(status)) { 7122e5b6d6dSopenharmony_ci result.quantity.setToDouble(amtNumber.getDouble(status)); 7132e5b6d6dSopenharmony_ci lnf->unit(amtUnit) 7142e5b6d6dSopenharmony_ci .unitWidth(getUnitWidth(fWidth)) 7152e5b6d6dSopenharmony_ci .formatImpl(&result, status); 7162e5b6d6dSopenharmony_ci } 7172e5b6d6dSopenharmony_ci DecimalFormat::fieldPositionHelper(result, pos, appendTo.length(), status); 7182e5b6d6dSopenharmony_ci appendTo.append(result.toTempString(status)); 7192e5b6d6dSopenharmony_ci return appendTo; 7202e5b6d6dSopenharmony_ci} 7212e5b6d6dSopenharmony_ci 7222e5b6d6dSopenharmony_ci 7232e5b6d6dSopenharmony_ci// Formats numeric time duration as 5:00:47 or 3:54. 7242e5b6d6dSopenharmony_ciUnicodeString &MeasureFormat::formatNumeric( 7252e5b6d6dSopenharmony_ci const Formattable *hms, // always length 3 7262e5b6d6dSopenharmony_ci int32_t bitMap, // 1=hour set, 2=minute set, 4=second set 7272e5b6d6dSopenharmony_ci UnicodeString &appendTo, 7282e5b6d6dSopenharmony_ci UErrorCode &status) const { 7292e5b6d6dSopenharmony_ci if (U_FAILURE(status)) { 7302e5b6d6dSopenharmony_ci return appendTo; 7312e5b6d6dSopenharmony_ci } 7322e5b6d6dSopenharmony_ci 7332e5b6d6dSopenharmony_ci UnicodeString pattern; 7342e5b6d6dSopenharmony_ci 7352e5b6d6dSopenharmony_ci double hours = hms[0].getDouble(status); 7362e5b6d6dSopenharmony_ci double minutes = hms[1].getDouble(status); 7372e5b6d6dSopenharmony_ci double seconds = hms[2].getDouble(status); 7382e5b6d6dSopenharmony_ci if (U_FAILURE(status)) { 7392e5b6d6dSopenharmony_ci return appendTo; 7402e5b6d6dSopenharmony_ci } 7412e5b6d6dSopenharmony_ci 7422e5b6d6dSopenharmony_ci // All possible combinations: "h", "m", "s", "hm", "hs", "ms", "hms" 7432e5b6d6dSopenharmony_ci if (bitMap == 5 || bitMap == 7) { // "hms" & "hs" (we add minutes if "hs") 7442e5b6d6dSopenharmony_ci pattern = cache->getNumericDateFormatters()->hourMinuteSecond; 7452e5b6d6dSopenharmony_ci hours = uprv_trunc(hours); 7462e5b6d6dSopenharmony_ci minutes = uprv_trunc(minutes); 7472e5b6d6dSopenharmony_ci } else if (bitMap == 3) { // "hm" 7482e5b6d6dSopenharmony_ci pattern = cache->getNumericDateFormatters()->hourMinute; 7492e5b6d6dSopenharmony_ci hours = uprv_trunc(hours); 7502e5b6d6dSopenharmony_ci } else if (bitMap == 6) { // "ms" 7512e5b6d6dSopenharmony_ci pattern = cache->getNumericDateFormatters()->minuteSecond; 7522e5b6d6dSopenharmony_ci minutes = uprv_trunc(minutes); 7532e5b6d6dSopenharmony_ci } else { // h m s, handled outside formatNumeric. No value is also an error. 7542e5b6d6dSopenharmony_ci status = U_INTERNAL_PROGRAM_ERROR; 7552e5b6d6dSopenharmony_ci return appendTo; 7562e5b6d6dSopenharmony_ci } 7572e5b6d6dSopenharmony_ci 7582e5b6d6dSopenharmony_ci const DecimalFormat *numberFormatter = dynamic_cast<const DecimalFormat*>(numberFormat->get()); 7592e5b6d6dSopenharmony_ci if (!numberFormatter) { 7602e5b6d6dSopenharmony_ci status = U_INTERNAL_PROGRAM_ERROR; 7612e5b6d6dSopenharmony_ci return appendTo; 7622e5b6d6dSopenharmony_ci } 7632e5b6d6dSopenharmony_ci number::LocalizedNumberFormatter numberFormatter2; 7642e5b6d6dSopenharmony_ci if (auto* lnf = numberFormatter->toNumberFormatter(status)) { 7652e5b6d6dSopenharmony_ci numberFormatter2 = lnf->integerWidth(number::IntegerWidth::zeroFillTo(2)); 7662e5b6d6dSopenharmony_ci } else { 7672e5b6d6dSopenharmony_ci return appendTo; 7682e5b6d6dSopenharmony_ci } 7692e5b6d6dSopenharmony_ci 7702e5b6d6dSopenharmony_ci FormattedStringBuilder fsb; 7712e5b6d6dSopenharmony_ci 7722e5b6d6dSopenharmony_ci UBool protect = false; 7732e5b6d6dSopenharmony_ci const int32_t patternLength = pattern.length(); 7742e5b6d6dSopenharmony_ci for (int32_t i = 0; i < patternLength; i++) { 7752e5b6d6dSopenharmony_ci char16_t c = pattern[i]; 7762e5b6d6dSopenharmony_ci 7772e5b6d6dSopenharmony_ci // Also set the proper field in this switch 7782e5b6d6dSopenharmony_ci // We don't use DateFormat.Field because this is not a date / time, is a duration. 7792e5b6d6dSopenharmony_ci double value = 0; 7802e5b6d6dSopenharmony_ci switch (c) { 7812e5b6d6dSopenharmony_ci case u'H': value = hours; break; 7822e5b6d6dSopenharmony_ci case u'm': value = minutes; break; 7832e5b6d6dSopenharmony_ci case u's': value = seconds; break; 7842e5b6d6dSopenharmony_ci } 7852e5b6d6dSopenharmony_ci 7862e5b6d6dSopenharmony_ci // There is not enough info to add Field(s) for the unit because all we have are plain 7872e5b6d6dSopenharmony_ci // text patterns. For example in "21:51" there is no text for something like "hour", 7882e5b6d6dSopenharmony_ci // while in something like "21h51" there is ("h"). But we can't really tell... 7892e5b6d6dSopenharmony_ci switch (c) { 7902e5b6d6dSopenharmony_ci case u'H': 7912e5b6d6dSopenharmony_ci case u'm': 7922e5b6d6dSopenharmony_ci case u's': 7932e5b6d6dSopenharmony_ci if (protect) { 7942e5b6d6dSopenharmony_ci fsb.appendChar16(c, kUndefinedField, status); 7952e5b6d6dSopenharmony_ci } else { 7962e5b6d6dSopenharmony_ci UnicodeString tmp; 7972e5b6d6dSopenharmony_ci if ((i + 1 < patternLength) && pattern[i + 1] == c) { // doubled 7982e5b6d6dSopenharmony_ci tmp = numberFormatter2.formatDouble(value, status).toString(status); 7992e5b6d6dSopenharmony_ci i++; 8002e5b6d6dSopenharmony_ci } else { 8012e5b6d6dSopenharmony_ci numberFormatter->format(value, tmp, status); 8022e5b6d6dSopenharmony_ci } 8032e5b6d6dSopenharmony_ci // TODO: Use proper Field 8042e5b6d6dSopenharmony_ci fsb.append(tmp, kUndefinedField, status); 8052e5b6d6dSopenharmony_ci } 8062e5b6d6dSopenharmony_ci break; 8072e5b6d6dSopenharmony_ci case u'\'': 8082e5b6d6dSopenharmony_ci // '' is escaped apostrophe 8092e5b6d6dSopenharmony_ci if ((i + 1 < patternLength) && pattern[i + 1] == c) { 8102e5b6d6dSopenharmony_ci fsb.appendChar16(c, kUndefinedField, status); 8112e5b6d6dSopenharmony_ci i++; 8122e5b6d6dSopenharmony_ci } else { 8132e5b6d6dSopenharmony_ci protect = !protect; 8142e5b6d6dSopenharmony_ci } 8152e5b6d6dSopenharmony_ci break; 8162e5b6d6dSopenharmony_ci default: 8172e5b6d6dSopenharmony_ci fsb.appendChar16(c, kUndefinedField, status); 8182e5b6d6dSopenharmony_ci } 8192e5b6d6dSopenharmony_ci } 8202e5b6d6dSopenharmony_ci 8212e5b6d6dSopenharmony_ci appendTo.append(fsb.toTempUnicodeString()); 8222e5b6d6dSopenharmony_ci 8232e5b6d6dSopenharmony_ci return appendTo; 8242e5b6d6dSopenharmony_ci} 8252e5b6d6dSopenharmony_ci 8262e5b6d6dSopenharmony_ciUnicodeString &MeasureFormat::formatMeasuresSlowTrack( 8272e5b6d6dSopenharmony_ci const Measure *measures, 8282e5b6d6dSopenharmony_ci int32_t measureCount, 8292e5b6d6dSopenharmony_ci UnicodeString& appendTo, 8302e5b6d6dSopenharmony_ci FieldPosition& pos, 8312e5b6d6dSopenharmony_ci UErrorCode& status) const { 8322e5b6d6dSopenharmony_ci if (U_FAILURE(status)) { 8332e5b6d6dSopenharmony_ci return appendTo; 8342e5b6d6dSopenharmony_ci } 8352e5b6d6dSopenharmony_ci FieldPosition dontCare(FieldPosition::DONT_CARE); 8362e5b6d6dSopenharmony_ci FieldPosition fpos(pos.getField()); 8372e5b6d6dSopenharmony_ci LocalArray<UnicodeString> results(new UnicodeString[measureCount], status); 8382e5b6d6dSopenharmony_ci int32_t fieldPositionFoundIndex = -1; 8392e5b6d6dSopenharmony_ci for (int32_t i = 0; i < measureCount; ++i) { 8402e5b6d6dSopenharmony_ci const NumberFormat *nf = cache->getIntegerFormat(); 8412e5b6d6dSopenharmony_ci if (i == measureCount - 1) { 8422e5b6d6dSopenharmony_ci nf = numberFormat->get(); 8432e5b6d6dSopenharmony_ci } 8442e5b6d6dSopenharmony_ci if (fieldPositionFoundIndex == -1) { 8452e5b6d6dSopenharmony_ci formatMeasure(measures[i], *nf, results[i], fpos, status); 8462e5b6d6dSopenharmony_ci if (U_FAILURE(status)) { 8472e5b6d6dSopenharmony_ci return appendTo; 8482e5b6d6dSopenharmony_ci } 8492e5b6d6dSopenharmony_ci if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) { 8502e5b6d6dSopenharmony_ci fieldPositionFoundIndex = i; 8512e5b6d6dSopenharmony_ci } 8522e5b6d6dSopenharmony_ci } else { 8532e5b6d6dSopenharmony_ci formatMeasure(measures[i], *nf, results[i], dontCare, status); 8542e5b6d6dSopenharmony_ci } 8552e5b6d6dSopenharmony_ci } 8562e5b6d6dSopenharmony_ci int32_t offset; 8572e5b6d6dSopenharmony_ci listFormatter->format( 8582e5b6d6dSopenharmony_ci results.getAlias(), 8592e5b6d6dSopenharmony_ci measureCount, 8602e5b6d6dSopenharmony_ci appendTo, 8612e5b6d6dSopenharmony_ci fieldPositionFoundIndex, 8622e5b6d6dSopenharmony_ci offset, 8632e5b6d6dSopenharmony_ci status); 8642e5b6d6dSopenharmony_ci if (U_FAILURE(status)) { 8652e5b6d6dSopenharmony_ci return appendTo; 8662e5b6d6dSopenharmony_ci } 8672e5b6d6dSopenharmony_ci // Fix up FieldPosition indexes if our field is found. 8682e5b6d6dSopenharmony_ci if (fieldPositionFoundIndex != -1 && offset != -1) { 8692e5b6d6dSopenharmony_ci pos.setBeginIndex(fpos.getBeginIndex() + offset); 8702e5b6d6dSopenharmony_ci pos.setEndIndex(fpos.getEndIndex() + offset); 8712e5b6d6dSopenharmony_ci } 8722e5b6d6dSopenharmony_ci return appendTo; 8732e5b6d6dSopenharmony_ci} 8742e5b6d6dSopenharmony_ci 8752e5b6d6dSopenharmony_ciMeasureFormat* U_EXPORT2 MeasureFormat::createCurrencyFormat(const Locale& locale, 8762e5b6d6dSopenharmony_ci UErrorCode& ec) { 8772e5b6d6dSopenharmony_ci if (U_FAILURE(ec)) { 8782e5b6d6dSopenharmony_ci return nullptr; 8792e5b6d6dSopenharmony_ci } 8802e5b6d6dSopenharmony_ci LocalPointer<CurrencyFormat> fmt(new CurrencyFormat(locale, ec), ec); 8812e5b6d6dSopenharmony_ci return fmt.orphan(); 8822e5b6d6dSopenharmony_ci} 8832e5b6d6dSopenharmony_ci 8842e5b6d6dSopenharmony_ciMeasureFormat* U_EXPORT2 MeasureFormat::createCurrencyFormat(UErrorCode& ec) { 8852e5b6d6dSopenharmony_ci if (U_FAILURE(ec)) { 8862e5b6d6dSopenharmony_ci return nullptr; 8872e5b6d6dSopenharmony_ci } 8882e5b6d6dSopenharmony_ci return MeasureFormat::createCurrencyFormat(Locale::getDefault(), ec); 8892e5b6d6dSopenharmony_ci} 8902e5b6d6dSopenharmony_ci 8912e5b6d6dSopenharmony_ciU_NAMESPACE_END 8922e5b6d6dSopenharmony_ci 8932e5b6d6dSopenharmony_ci#endif /* #if !UCONFIG_NO_FORMATTING */ 894