• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 
16 #include "number_format_addon.h"
17 
18 #include "i18n_hilog.h"
19 #include "utils.h"
20 #include "variable_converter.h"
21 
22 using namespace OHOS;
23 using namespace Global;
24 using namespace I18n;
25 
UnwrapAddon(ani_env * env,ani_object object,const std::string & name)26 NumberFormatAddon* NumberFormatAddon::UnwrapAddon(ani_env *env, ani_object object, const std::string &name)
27 {
28     ani_long ptr;
29     if (ANI_OK != env->Object_GetFieldByName_Long(object, name.c_str(), &ptr)) {
30         HILOG_ERROR_I18N("Get Long '%{public}s' failed", name.c_str());
31         return nullptr;
32     }
33     return reinterpret_cast<NumberFormatAddon*>(ptr);
34 }
35 
NumberFormat_Format(ani_env * env,ani_object object,ani_double number)36 ani_string NumberFormatAddon::NumberFormat_Format(ani_env *env, ani_object object, ani_double number)
37 {
38     NumberFormatAddon *obj = UnwrapAddon(env, object, "nativeNumberFormat");
39     if (obj == nullptr || obj->numberfmt_ == nullptr) {
40         HILOG_ERROR_I18N("FormatNumber: Get NumberFormat object failed");
41         return nullptr;
42     }
43 
44     std::string str = obj->numberfmt_->Format(number);
45     return VariableConverter::StringToAniStr(env, str);
46 }
47 
NumberFormat_FormatRange(ani_env * env,ani_object object,ani_double startRange,ani_double endRange)48 ani_string NumberFormatAddon::NumberFormat_FormatRange(ani_env *env, ani_object object,
49     ani_double startRange, ani_double endRange)
50 {
51     NumberFormatAddon *obj = UnwrapAddon(env, object, "nativeNumberFormat");
52     if (obj == nullptr || obj->numberfmt_ == nullptr) {
53         HILOG_ERROR_I18N("FormatRangeNumber: Get NumberFormat object failed");
54         return nullptr;
55     }
56 
57     std::string str = obj->numberfmt_->FormatRange(startRange, endRange);
58     return VariableConverter::StringToAniStr(env, str);
59 }
60 
NumberFormat_ResolvedOptions(ani_env * env,ani_object object)61 ani_object NumberFormatAddon::NumberFormat_ResolvedOptions(ani_env *env, ani_object object)
62 {
63     NumberFormatAddon *obj = UnwrapAddon(env, object, "nativeNumberFormat");
64     if (obj == nullptr || obj->numberfmt_ == nullptr) {
65         HILOG_ERROR_I18N("GetNumberResolvedOptions: Get NumberFormat object failed");
66         return nullptr;
67     }
68     std::map<std::string, std::string> options = {};
69     obj->numberfmt_->GetResolvedOptions(options);
70 
71     static const char *className = "L@ohos/intl/intl/NumberOptionsInner;";
72     ani_class cls;
73     if (ANI_OK != env->FindClass(className, &cls)) {
74         HILOG_ERROR_I18N("Find class '%{public}s' failed", className);
75         return nullptr;
76     }
77 
78     ani_method ctor;
79     if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", nullptr, &ctor)) {
80         HILOG_ERROR_I18N("Find method '<ctor>' failed");
81         return nullptr;
82     }
83 
84     ani_object numberOptions;
85     if (ANI_OK != env->Object_New(cls, ctor, &numberOptions)) {
86         HILOG_ERROR_I18N("New object '%{public}s' failed", className);
87         return nullptr;
88     }
89 
90     std::vector<std::string> keys = {
91         "locale", "currency", "currencySign", "currencyDisplay", "unit", "unitDisplay", "unitUsage",
92         "signDisplay", "compactDisplay", "notation", "localeMatcher", "style", "numberingSystem",
93         "roundingPriority", "roundingMode", "minimumIntegerDigits", "minimumFractionDigits", "maximumFractionDigits",
94         "minimumSignificantDigits", "maximumSignificantDigits", "roundingIncrement"
95     };
96 
97     for (const auto& key : keys) {
98         if (options.find(key) != options.end()) {
99             if (key == "minimumIntegerDigits" || key == "minimumFractionDigits" ||
100                 key == "maximumFractionDigits" || key == "minimumSignificantDigits" ||
101                 key == "maximumSignificantDigits" || key == "roundingIncrement") {
102                 VariableConverter::SetNumberMember(env, numberOptions, key, options[key]);
103             } else {
104                 VariableConverter::SetStringMember(env, numberOptions, key, options[key]);
105             }
106         }
107     }
108     VariableConverter::SetBooleanMember(env, numberOptions, "useGrouping", options["useGrouping"]);
109     return numberOptions;
110 }
111 
NumberFormat_Create(ani_env * env,ani_object object)112 ani_object NumberFormatAddon::NumberFormat_Create(ani_env *env, [[maybe_unused]] ani_object object)
113 {
114     std::vector<std::string> localeTags;
115     std::map<std::string, std::string> map = {};
116     std::unique_ptr<NumberFormatAddon> obj = std::make_unique<NumberFormatAddon>();
117     obj->numberfmt_ = std::make_unique<NumberFormat>(localeTags, map);
118 
119     static const char *className = "L@ohos/intl/intl/NumberFormat;";
120     ani_object numberFormatObject = VariableConverter::CreateAniObject(env, className, obj.get());
121     obj.release();
122     return numberFormatObject;
123 }
124 
GetNumberFormatOptions(ani_env * env,ani_object options)125 static std::map<std::string, std::string> GetNumberFormatOptions(ani_env *env, ani_object options)
126 {
127     std::map<std::string, std::string> map;
128     ani_boolean isUndefined;
129     if (ANI_OK != env->Reference_IsUndefined(options, &isUndefined)) {
130         HILOG_ERROR_I18N("Reference IsUndefined failed");
131         return map;
132     }
133     if (!isUndefined) {
134         std::vector<std::string> stringKeys = {
135             "locale", "currency", "currencySign", "currencyDisplay", "unit", "unitDisplay", "unitUsage",
136             "signDisplay", "compactDisplay", "notation", "localeMatcher", "style", "numberingSystem"
137         };
138         for (const auto& key : stringKeys) {
139             std::string value;
140             if (VariableConverter::GetStringMember(env, options, key, value)) {
141                 map.insert(std::make_pair(key, value));
142             }
143         }
144 
145         std::vector<std::pair<std::string, int>> intKeys = {
146             {"minimumIntegerDigits", 0}, {"minimumFractionDigits", 0}, {"maximumFractionDigits", 0},
147             {"minimumSignificantDigits", 0}, {"maximumSignificantDigits", 0}, {"roundingIncrement", 0}
148         };
149         for (auto& [key, value] : intKeys) {
150             if (VariableConverter::GetNumberMember(env, options, key, value)) {
151                 map.insert(std::make_pair(key, std::to_string(value)));
152             }
153         }
154 
155         bool useGrouping;
156         if (VariableConverter::GetBooleanMember(env, options, "useGrouping", useGrouping)) {
157             map.insert(std::make_pair("useGrouping", useGrouping ? "true" : "false"));
158         }
159     }
160     return map;
161 }
162 
NumberFormat_CreateWithParam(ani_env * env,ani_object object,ani_object locale,ani_object options)163 ani_object NumberFormatAddon::NumberFormat_CreateWithParam(ani_env *env, [[maybe_unused]] ani_object object,
164     ani_object locale, ani_object options)
165 {
166     std::vector<std::string> localeTags = VariableConverter::GetLocaleTags(env, locale);
167     std::map<std::string, std::string> map = GetNumberFormatOptions(env, options);
168 
169     std::unique_ptr<NumberFormatAddon> obj = std::make_unique<NumberFormatAddon>();
170     obj->numberfmt_ = std::make_unique<NumberFormat>(localeTags, map);
171 
172     static const char *className = "L@ohos/intl/intl/NumberFormat;";
173     ani_object numberFormatObject = VariableConverter::CreateAniObject(env, className, obj.get());
174     obj.release();
175     return numberFormatObject;
176 }
177 
BindContext_NumberFormat(ani_env * env)178 ani_status NumberFormatAddon::BindContext_NumberFormat(ani_env *env)
179 {
180     static const char *className = "L@ohos/intl/intl/NumberFormat;";
181     ani_class cls;
182     if (ANI_OK != env->FindClass(className, &cls)) {
183         HILOG_ERROR_I18N("Find class '%{public}s' failed", className);
184         return ANI_ERROR;
185     }
186 
187     std::array methods = {
188         ani_native_function {"create", ":L@ohos/intl/intl/NumberFormat;",
189             reinterpret_cast<void *>(NumberFormat_Create) },
190         ani_native_function {"create",
191             "Lstd/core/Object;L@ohos/intl/intl/NumberOptions;:L@ohos/intl/intl/NumberFormat;",
192             reinterpret_cast<void *>(NumberFormat_CreateWithParam) },
193         ani_native_function {"format", nullptr, reinterpret_cast<void *>(NumberFormat_Format) },
194         ani_native_function {"formatRange", nullptr, reinterpret_cast<void *>(NumberFormat_FormatRange) },
195         ani_native_function {"resolvedOptions", nullptr, reinterpret_cast<void *>(NumberFormat_ResolvedOptions) },
196     };
197 
198     if (ANI_OK != env->Class_BindNativeMethods(cls, methods.data(), methods.size())) {
199         HILOG_ERROR_I18N("Cannot bind native methods to '%{public}s'", className);
200         return ANI_ERROR;
201     };
202     return ANI_OK;
203 }
204