1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "locale_config.h"
16 
17 #include <cctype>
18 #include <sstream>
19 #include "i18n_hilog.h"
20 #include "ohos/init_data.h"
21 #include "parameter.h"
22 #include "unicode/ucurr.h"
23 #include "unicode/uenum.h"
24 #include "unicode/utypes.h"
25 #include "utils.h"
26 #include "number_format.h"
27 
28 namespace OHOS {
29 namespace Global {
30 namespace I18n {
31 const char* NumberFormat::DEVICE_TYPE_NAME = "const.product.devicetype";
32 std::unordered_map<std::string, std::string> NumberFormat::numToCurrency = {};
33 bool NumberFormat::icuInitialized = NumberFormat::Init();
34 
35 std::unordered_map<std::string, UNumberUnitWidth> NumberFormat::unitStyle = {
36     { "long", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
37     { "short", UNumberUnitWidth::UNUM_UNIT_WIDTH_SHORT },
38     { "narrow", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW }
39 };
40 
41 std::unordered_map<std::string, UNumberUnitWidth> NumberFormat::currencyStyle = {
42     { "symbol", UNumberUnitWidth::UNUM_UNIT_WIDTH_SHORT },
43     { "code", UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE },
44     { "name", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
45     { "narrowSymbol", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW }
46 };
47 
48 std::unordered_map<std::string, UNumberSignDisplay> NumberFormat::signAutoStyle = {
49     { "auto", UNumberSignDisplay::UNUM_SIGN_AUTO },
50     { "never", UNumberSignDisplay::UNUM_SIGN_NEVER },
51     { "always", UNumberSignDisplay::UNUM_SIGN_ALWAYS },
52     { "exceptZero", UNumberSignDisplay::UNUM_SIGN_EXCEPT_ZERO }
53 };
54 
55 std::unordered_map<std::string, UNumberSignDisplay> NumberFormat::signAccountingStyle = {
56     { "auto", UNumberSignDisplay::UNUM_SIGN_ACCOUNTING },
57     { "never", UNumberSignDisplay::UNUM_SIGN_NEVER },
58     { "always", UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_ALWAYS },
59     { "exceptZero", UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO }
60 };
61 
62 std::unordered_map<UMeasurementSystem, std::string> NumberFormat::measurementSystem = {
63     { UMeasurementSystem::UMS_SI, "SI" },
64     { UMeasurementSystem::UMS_US, "US" },
65     { UMeasurementSystem::UMS_UK, "UK" },
66 };
67 
68 std::unordered_map<std::string, UNumberUnitWidth> NumberFormat::defaultUnitStyle = {
69     { "tablet", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
70     { "2in1", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
71     { "tv", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
72     { "pc", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
73     { "wearable", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW },
74     { "liteWearable", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW },
75     { "watch", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW }
76 };
77 
78 std::unordered_map<std::string, UNumberUnitWidth> NumberFormat::defaultCurrencyStyle = {
79     { "wearable", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW },
80     { "liteWearable", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW },
81     { "watch", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW }
82 };
83 
84 std::map<std::string, std::string> NumberFormat::RelativeTimeFormatConfigs = {
85     { "numeric", "auto" }
86 };
87 
NumberFormat(const std::vector<std::string> & localeTags,std::map<std::string,std::string> & configs)88 NumberFormat::NumberFormat(const std::vector<std::string> &localeTags, std::map<std::string, std::string> &configs)
89 {
90     SetDefaultStyle();
91     UErrorCode status = U_ZERO_ERROR;
92     std::unique_ptr<icu::LocaleBuilder> builder = nullptr;
93     builder = std::make_unique<icu::LocaleBuilder>();
94     ParseConfigs(configs);
95     for (size_t i = 0; i < localeTags.size(); i++) {
96         std::string curLocale = localeTags[i];
97         locale = icu::Locale::forLanguageTag(icu::StringPiece(curLocale), status);
98         if (status != U_ZERO_ERROR) {
99             status = U_ZERO_ERROR;
100             continue;
101         }
102         if (LocaleInfo::allValidLocales.count(locale.getLanguage()) > 0) {
103             localeInfo = std::make_unique<LocaleInfo>(curLocale, configs);
104             CreateRelativeTimeFormat(curLocale);
105             if (!localeInfo->InitSuccess()) {
106                 continue;
107             }
108             locale = localeInfo->GetLocale();
109             localeBaseName = localeInfo->GetBaseName();
110             numberFormat = icu::number::NumberFormatter::withLocale(locale);
111             icu::MeasureUnit::getAvailable(unitArray, MAX_UNIT_NUM, status);
112             if (!U_SUCCESS(status)) {
113                 status = U_ZERO_ERROR;
114                 continue;
115             }
116             createSuccess = true;
117             break;
118         }
119     }
120     if (!createSuccess) {
121         std::string systemLocale = LocaleConfig::GetSystemLocale();
122         localeInfo = std::make_unique<LocaleInfo>(systemLocale, configs);
123         CreateRelativeTimeFormat(systemLocale);
124         if (localeInfo->InitSuccess()) {
125             locale = localeInfo->GetLocale();
126             localeBaseName = localeInfo->GetBaseName();
127             numberFormat = icu::number::NumberFormatter::withLocale(locale);
128             icu::MeasureUnit::getAvailable(unitArray, MAX_UNIT_NUM, status);
129             if (U_SUCCESS(status)) {
130                 createSuccess = true;
131             }
132         }
133     }
134     if (createSuccess) {
135         InitProperties();
136     }
137 }
138 
~NumberFormat()139 NumberFormat::~NumberFormat()
140 {
141 }
142 
CreateRelativeTimeFormat(const std::string & locale)143 void NumberFormat::CreateRelativeTimeFormat(const std::string& locale)
144 {
145     if (unitUsage == "elapsed-time-second") {
146         std::vector<std::string> locales = { locale };
147         relativeTimeFormat = std::make_unique<RelativeTimeFormat>(locales,
148             RelativeTimeFormatConfigs);
149     }
150 }
151 
InitProperties()152 void NumberFormat::InitProperties()
153 {
154     if (!currency.empty()) {
155         UErrorCode status = U_ZERO_ERROR;
156         numberFormat =
157             numberFormat.unit(icu::CurrencyUnit(icu::UnicodeString(currency.c_str()).getBuffer(), status));
158         if (currencyDisplay != UNumberUnitWidth::UNUM_UNIT_WIDTH_SHORT) {
159             numberFormat = numberFormat.unitWidth(currencyDisplay);
160         }
161     }
162     if (!styleString.empty() && styleString == "percent") {
163     // 2 is the power of ten
164         numberFormat = numberFormat.unit(icu::NoUnit::percent()).scale(icu::number::Scale::powerOfTen(2)).precision(
165             icu::number::Precision::fixedFraction(0));
166     }
167     if (!styleString.empty() && styleString == "unit") {
168         for (icu::MeasureUnit curUnit : unitArray) {
169             if (!strcmp(curUnit.getSubtype(), unit.c_str())) {
170                 numberFormat = numberFormat.unit(curUnit);
171                 unitType = curUnit.getType();
172             }
173         }
174         UErrorCode status = U_ZERO_ERROR;
175         UMeasurementSystem measSys = ulocdata_getMeasurementSystem(localeBaseName.c_str(), &status);
176         if (U_SUCCESS(status) && measSys >= 0) {
177             unitMeasSys = measurementSystem[measSys];
178         }
179         numberFormat = numberFormat.unitWidth(unitDisplay);
180         numberFormat = numberFormat.precision(icu::number::Precision::maxFraction(DEFAULT_FRACTION_DIGITS));
181     }
182     if (!useGrouping.empty()) {
183         numberFormat = numberFormat.grouping((useGrouping == "true") ?
184             UNumberGroupingStrategy::UNUM_GROUPING_AUTO : UNumberGroupingStrategy::UNUM_GROUPING_OFF);
185     }
186     if (!currencySign.empty() || !signDisplayString.empty()) {
187         numberFormat = numberFormat.sign(signDisplay);
188     }
189     if (!notationString.empty()) {
190         numberFormat = numberFormat.notation(notation);
191     }
192     InitDigitsProperties();
193 }
194 
InitDigitsProperties()195 void NumberFormat::InitDigitsProperties()
196 {
197     int32_t status = 0;
198     if (!maximumSignificantDigits.empty() || !minimumSignificantDigits.empty()) {
199         int32_t maxSignificantDigits = ConvertString2Int(maximumSignificantDigits, status);
200         if (status == 0) {
201             numberFormat = numberFormat.precision(icu::number::Precision::maxSignificantDigits(maxSignificantDigits));
202         }
203 
204         status = 0;
205         int32_t minSignificantDigits = ConvertString2Int(minimumSignificantDigits, status);
206         if (status == 0) {
207             numberFormat = numberFormat.precision(icu::number::Precision::minSignificantDigits(minSignificantDigits));
208         }
209     } else {
210         int32_t minIntegerDigits = ConvertString2Int(minimumIntegerDigits, status);
211         if (status == 0 && minIntegerDigits > 1) {
212             numberFormat =
213                 numberFormat.integerWidth(icu::number::IntegerWidth::zeroFillTo(minIntegerDigits));
214         }
215 
216         int32_t minFdStatus = 0;
217         int32_t minFractionDigits = ConvertString2Int(minimumFractionDigits, minFdStatus);
218         int32_t maxFdStatus = 0;
219         int32_t maxFractionDigits = ConvertString2Int(maximumFractionDigits, maxFdStatus);
220         if (minFdStatus == 0 || maxFdStatus == 0) {
221             isSetFraction = true;
222         }
223         if (minFdStatus == 0 && maxFdStatus != 0) {
224             numberFormat =
225                 numberFormat.precision(icu::number::Precision::minFraction(minFractionDigits));
226         } else if (minFdStatus != 0 && maxFdStatus == 0) {
227             numberFormat =
228                 numberFormat.precision(icu::number::Precision::maxFraction(maxFractionDigits));
229         } else if (minFdStatus == 0 && maxFdStatus == 0) {
230             numberFormat =
231                 numberFormat.precision(icu::number::Precision::minMaxFraction(minFractionDigits, maxFractionDigits));
232         }
233     }
234 }
235 
ParseConfigs(std::map<std::string,std::string> & configs)236 void NumberFormat::ParseConfigs(std::map<std::string, std::string> &configs)
237 {
238     if (configs.count("signDisplay") > 0) {
239         signDisplayString = configs["signDisplay"];
240     }
241     if (signAutoStyle.count(signDisplayString) > 0) {
242         signDisplay = signAutoStyle[signDisplayString];
243     }
244     if (configs.count("style") > 0) {
245         styleString = configs["style"];
246     }
247     if (styleString == "unit" && configs.count("unit") > 0) {
248         unit = configs["unit"];
249         if (configs.count("unitDisplay") > 0) {
250             unitDisplayString = configs["unitDisplay"];
251             if (unitStyle.count(unitDisplayString) > 0) {
252                 unitDisplay = unitStyle[unitDisplayString];
253             }
254         }
255         if (configs.count("unitUsage") > 0) {
256             unitUsage = configs["unitUsage"];
257         }
258     }
259     if (styleString == "currency" && configs.count("currency") > 0) {
260         currency = GetCurrencyFromConfig(configs["currency"]);
261         if (configs.count("currencySign") > 0) {
262             currencySign = configs["currencySign"];
263         }
264         if (currencySign.compare("accounting") == 0 && signAccountingStyle.count(signDisplayString) > 0) {
265             signDisplay = signAccountingStyle[signDisplayString];
266         }
267         if (configs.count("currencyDisplay") > 0 && currencyStyle.count(configs["currencyDisplay"]) > 0) {
268             currencyDisplayString = configs["currencyDisplay"];
269             currencyDisplay = currencyStyle[currencyDisplayString];
270         }
271     }
272     ParseDigitsConfigs(configs);
273 }
274 
ParseDigitsConfigs(std::map<std::string,std::string> & configs)275 void NumberFormat::ParseDigitsConfigs(std::map<std::string, std::string> &configs)
276 {
277     if (configs.count("notation") > 0) {
278         notationString = configs["notation"];
279         if (notationString == "scientific") {
280             notation = icu::number::Notation::scientific();
281         } else if (notationString == "engineering") {
282             notation = icu::number::Notation::engineering();
283         }
284         if (notationString == "compact") {
285             if (configs.count("compactDisplay") > 0) {
286                 compactDisplay = configs["compactDisplay"];
287             }
288             if (compactDisplay == "long") {
289                 notation = icu::number::Notation::compactLong();
290             } else {
291                 notation = icu::number::Notation::compactShort();
292             }
293         }
294     }
295     if (configs.count("minimumIntegerDigits") > 0) {
296         minimumIntegerDigits = configs["minimumIntegerDigits"];
297     }
298     if (configs.count("minimumFractionDigits") > 0) {
299         minimumFractionDigits = configs["minimumFractionDigits"];
300     }
301     if (configs.count("maximumFractionDigits") > 0) {
302         maximumFractionDigits = configs["maximumFractionDigits"];
303     }
304     if (configs.count("minimumSignificantDigits") > 0) {
305         minimumSignificantDigits = configs["minimumSignificantDigits"];
306     }
307     if (configs.count("maximumSignificantDigits") > 0) {
308         maximumSignificantDigits = configs["maximumSignificantDigits"];
309     }
310     if (configs.count("numberingSystem") > 0) {
311         numberingSystem = configs["numberingSystem"];
312     }
313     if (configs.count("useGrouping") > 0) {
314         useGrouping = configs["useGrouping"];
315     }
316     if (configs.count("localeMatcher") > 0) {
317         localeMatcher = configs["localeMatcher"];
318     }
319 }
320 
SetUnit(std::string & preferredUnit)321 void NumberFormat::SetUnit(std::string &preferredUnit)
322 {
323     if (preferredUnit.empty()) {
324         return;
325     }
326     for (icu::MeasureUnit curUnit : unitArray) {
327         if (!strcmp(curUnit.getSubtype(), preferredUnit.c_str())) {
328             numberFormat = numberFormat.unit(curUnit);
329         }
330     }
331 }
332 
Format(double number)333 std::string NumberFormat::Format(double number)
334 {
335     if (!createSuccess) {
336         return PseudoLocalizationProcessor("");
337     }
338     double finalNumber = number;
339     std::string finalUnit = unit;
340     if ((unitUsage == "size-file-byte" || unitUsage == "size-shortfile-byte") && ConvertByte(finalNumber, finalUnit)) {
341         SetUnit(finalUnit);
342         SetPrecisionWithByte(finalNumber, finalUnit);
343     } else if (unitUsage == "elapsed-time-second" && ConvertDate(finalNumber, finalUnit) &&
344         relativeTimeFormat != nullptr) {
345         return relativeTimeFormat->Format(finalNumber, finalUnit);
346     } else if (!unitUsage.empty()) {
347         std::vector<std::string> preferredUnits;
348         if (unitUsage == "default") {
349             GetDefaultPreferredUnit(localeInfo->GetRegion(), unitType, preferredUnits);
350         } else {
351             GetPreferredUnit(localeInfo->GetRegion(), unitUsage, preferredUnits);
352         }
353         std::map<double, std::string> preferredValuesOverOne;
354         std::map<double, std::string> preferredValuesUnderOne;
355         double num = number;
356         for (size_t i = 0; i < preferredUnits.size(); i++) {
357             int status = Convert(num, unit, unitMeasSys, preferredUnits[i], unitMeasSys);
358             if (!status) {
359                 continue;
360             }
361             if (num >= 1) {
362                 preferredValuesOverOne.insert(std::make_pair(num, preferredUnits[i]));
363             } else {
364                 preferredValuesUnderOne.insert(std::make_pair(num, preferredUnits[i]));
365             }
366         }
367         std::string preferredUnit;
368         if (preferredValuesOverOne.size() > 0) {
369             finalNumber = preferredValuesOverOne.begin()->first;
370             preferredUnit = preferredValuesOverOne.begin()->second;
371         } else if (preferredValuesUnderOne.size() > 0) {
372             finalNumber = preferredValuesUnderOne.rbegin()->first;
373             preferredUnit = preferredValuesUnderOne.rbegin()->second;
374         }
375         SetUnit(preferredUnit);
376     }
377     std::string result;
378     UErrorCode status = U_ZERO_ERROR;
379     numberFormat.formatDouble(finalNumber, status).toString(status).toUTF8String(result);
380     return PseudoLocalizationProcessor(result);
381 }
382 
GetResolvedOptions(std::map<std::string,std::string> & map)383 void NumberFormat::GetResolvedOptions(std::map<std::string, std::string> &map)
384 {
385     map.insert(std::make_pair("locale", localeBaseName));
386     if (!styleString.empty()) {
387         map.insert(std::make_pair("style", styleString));
388     }
389     if (!currency.empty()) {
390         map.insert(std::make_pair("currency", currency));
391     }
392     if (!currencySign.empty()) {
393         map.insert(std::make_pair("currencySign", currencySign));
394     }
395     if (!currencyDisplayString.empty()) {
396         map.insert(std::make_pair("currencyDisplay", currencyDisplayString));
397     }
398     if (!signDisplayString.empty()) {
399         map.insert(std::make_pair("signDisplay", signDisplayString));
400     }
401     if (!compactDisplay.empty()) {
402         map.insert(std::make_pair("compactDisplay", compactDisplay));
403     }
404     if (!unitDisplayString.empty()) {
405         map.insert(std::make_pair("unitDisplay", unitDisplayString));
406     }
407     if (!unitUsage.empty()) {
408         map.insert(std::make_pair("unitUsage", unitUsage));
409     }
410     if (!unit.empty()) {
411         map.insert(std::make_pair("unit", unit));
412     }
413     GetDigitsResolvedOptions(map);
414 }
415 
GetDigitsResolvedOptions(std::map<std::string,std::string> & map)416 void NumberFormat::GetDigitsResolvedOptions(std::map<std::string, std::string> &map)
417 {
418     if (!numberingSystem.empty()) {
419         map.insert(std::make_pair("numberingSystem", numberingSystem));
420     } else if (!(localeInfo->GetNumberingSystem()).empty()) {
421         map.insert(std::make_pair("numberingSystem", localeInfo->GetNumberingSystem()));
422     } else {
423         UErrorCode status = U_ZERO_ERROR;
424         auto numSys = std::unique_ptr<icu::NumberingSystem>(icu::NumberingSystem::createInstance(locale, status));
425         if (U_SUCCESS(status)) {
426             map.insert(std::make_pair("numberingSystem", numSys->getName()));
427         }
428     }
429     if (!useGrouping.empty()) {
430         map.insert(std::make_pair("useGrouping", useGrouping));
431     }
432     if (!minimumIntegerDigits.empty()) {
433         map.insert(std::make_pair("minimumIntegerDigits", minimumIntegerDigits));
434     }
435     if (!minimumFractionDigits.empty()) {
436         map.insert(std::make_pair("minimumFractionDigits", minimumFractionDigits));
437     }
438     if (!maximumFractionDigits.empty()) {
439         map.insert(std::make_pair("maximumFractionDigits", maximumFractionDigits));
440     }
441     if (!minimumSignificantDigits.empty()) {
442         map.insert(std::make_pair("minimumSignificantDigits", minimumSignificantDigits));
443     }
444     if (!maximumSignificantDigits.empty()) {
445         map.insert(std::make_pair("maximumSignificantDigits", maximumSignificantDigits));
446     }
447     if (!localeMatcher.empty()) {
448         map.insert(std::make_pair("localeMatcher", localeMatcher));
449     }
450     if (!notationString.empty()) {
451         map.insert(std::make_pair("notation", notationString));
452     }
453 }
454 
SetPrecisionWithByte(double number,const std::string & finalUnit)455 void NumberFormat::SetPrecisionWithByte(double number, const std::string& finalUnit)
456 {
457     if (isSetFraction) {
458         return;
459     }
460     int32_t FractionDigits = -1;
461     // 100 is the threshold between different decimal
462     if (finalUnit == "byte" || number >= 100) {
463         FractionDigits = 0;
464     } else if (number < 1) {
465         // 2 is the number of significant digits in the decimal
466         FractionDigits = 2;
467     // 10 is the threshold between different decimal
468     } else if (number < 10) {
469         if (unitUsage == "size-shortfile-byte") {
470             FractionDigits = 1;
471         } else {
472             // 2 is the number of significant digits in the decimal
473             FractionDigits = 2;
474         }
475     } else {
476         if (unitUsage == "size-shortfile-byte") {
477             FractionDigits = 0;
478         } else {
479             // 2 is the number of significant digits in the decimal
480             FractionDigits = 2;
481         }
482     }
483     if (FractionDigits != -1) {
484         numberFormat = numberFormat.precision(icu::number::Precision::minMaxFraction(FractionDigits, FractionDigits));
485     }
486 }
487 
GetCurrency() const488 std::string NumberFormat::GetCurrency() const
489 {
490     return currency;
491 }
492 
GetCurrencySign() const493 std::string NumberFormat::GetCurrencySign() const
494 {
495     return currencySign;
496 }
497 
GetStyle() const498 std::string NumberFormat::GetStyle() const
499 {
500     return styleString;
501 }
502 
GetNumberingSystem() const503 std::string NumberFormat::GetNumberingSystem() const
504 {
505     return numberingSystem;
506 }
507 
GetUseGrouping() const508 std::string NumberFormat::GetUseGrouping() const
509 {
510     return useGrouping;
511 }
512 
GetMinimumIntegerDigits() const513 std::string NumberFormat::GetMinimumIntegerDigits() const
514 {
515     return minimumIntegerDigits;
516 }
517 
GetMinimumFractionDigits() const518 std::string NumberFormat::GetMinimumFractionDigits() const
519 {
520     return minimumFractionDigits;
521 }
522 
GetMaximumFractionDigits() const523 std::string NumberFormat::GetMaximumFractionDigits() const
524 {
525     return maximumFractionDigits;
526 }
527 
GetMinimumSignificantDigits() const528 std::string NumberFormat::GetMinimumSignificantDigits() const
529 {
530     return minimumSignificantDigits;
531 }
532 
GetMaximumSignificantDigits() const533 std::string NumberFormat::GetMaximumSignificantDigits() const
534 {
535     return maximumSignificantDigits;
536 }
537 
GetLocaleMatcher() const538 std::string NumberFormat::GetLocaleMatcher() const
539 {
540     return localeMatcher;
541 }
542 
Init()543 bool NumberFormat::Init()
544 {
545     SetHwIcuDirectory();
546     return true;
547 }
548 
SetDefaultStyle()549 void NumberFormat::SetDefaultStyle()
550 {
551     char value[BUFFER_LEN];
552     int code = GetParameter(DEVICE_TYPE_NAME, "", value, BUFFER_LEN);
553     if (code > 0) {
554         std::string deviceType = value;
555         if (defaultUnitStyle.find(deviceType) != defaultUnitStyle.end()) {
556             unitDisplay = defaultUnitStyle[deviceType];
557         }
558         if (defaultCurrencyStyle.find(deviceType) != defaultCurrencyStyle.end()) {
559             currencyDisplay = defaultCurrencyStyle[deviceType];
560         }
561     }
562 }
563 
ReadISO4217Ddatas()564 bool NumberFormat::ReadISO4217Ddatas()
565 {
566     if (numToCurrency.size()) {
567         return true;
568     }
569     UErrorCode status = U_ZERO_ERROR;
570     const char *currentCurrency;
571     UEnumeration *currencies = ucurr_openISOCurrencies(UCURR_ALL, &status);
572     if (U_FAILURE(status)) {
573         return false;
574     }
575 
576     UChar code[CURRENCY_LEN + 1];  // +1 includes the NUL
577     int32_t length = 0;
578     while ((currentCurrency = uenum_next(currencies, &length, &status)) != NULL) {
579         u_charsToUChars(currentCurrency, code, length + 1);  // +1 includes the NUL
580         int32_t numCode = ucurr_getNumericCode(code);
581         if (numCode == 0) {
582             continue;
583         }
584         std::stringstream ss;
585         ss << std::setw(CURRENCY_LEN) << std::setfill('0') << numCode; // fill with '0'
586         numToCurrency.insert(std::make_pair<std::string, std::string>(ss.str(), currentCurrency));
587     }
588     uenum_close(currencies);
589     return !numToCurrency.empty();
590 }
591 
GetCurrencyFromConfig(const std::string & currency)592 std::string NumberFormat::GetCurrencyFromConfig(const std::string& currency)
593 {
594     if (currency.size() != CURRENCY_LEN) {
595         HILOG_ERROR_I18N("Invalid currency code : %{public}s", currency.c_str());
596         return "";
597     }
598     bool isAlpha = true;
599     for (auto c : currency) {
600         isAlpha = std::isalpha(c);
601         if (!isAlpha) {
602             break;
603         }
604     }
605     if (isAlpha) {
606         return currency;
607     }
608     if (ReadISO4217Ddatas() && numToCurrency.find(currency) != numToCurrency.end()) {
609         return numToCurrency[currency];
610     }
611     HILOG_ERROR_I18N("Invalid currency code : %{public}s", currency.c_str());
612     return "";
613 }
614 } // namespace I18n
615 } // namespace Global
616 } // namespace OHOS
617