• 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 #include "collator_addon.h"
16 
17 #include "error_util.h"
18 #include "intl_addon.h"
19 #include "i18n_hilog.h"
20 #include "js_utils.h"
21 
22 namespace OHOS {
23 namespace Global {
24 namespace I18n {
25 static thread_local napi_ref g_constructor = nullptr;
26 
CollatorAddon()27 CollatorAddon::CollatorAddon() : env_(nullptr) {}
28 
~CollatorAddon()29 CollatorAddon::~CollatorAddon()
30 {
31 }
32 
Destructor(napi_env env,void * nativeObject,void * hint)33 void CollatorAddon::Destructor(napi_env env, void *nativeObject, void *hint)
34 {
35     if (!nativeObject) {
36         return;
37     }
38     delete reinterpret_cast<CollatorAddon *>(nativeObject);
39     nativeObject = nullptr;
40 }
41 
InitCollator(napi_env env,napi_value exports)42 napi_value CollatorAddon::InitCollator(napi_env env, napi_value exports)
43 {
44     napi_property_descriptor properties[] = {
45         DECLARE_NAPI_FUNCTION("compare", CompareString),
46         DECLARE_NAPI_FUNCTION("resolvedOptions", GetCollatorResolvedOptions),
47         DECLARE_NAPI_STATIC_FUNCTION("supportedLocalesOf", SupportedLocalesOf),
48     };
49 
50     napi_value constructor;
51     napi_status status = napi_define_class(env, "Collator", NAPI_AUTO_LENGTH, CollatorConstructor, nullptr,
52         sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
53     if (status != napi_ok) {
54         HILOG_ERROR_I18N("Define class failed when InitCollator");
55         return nullptr;
56     }
57 
58     status = napi_set_named_property(env, exports, "Collator", constructor);
59     if (status != napi_ok) {
60         HILOG_ERROR_I18N("Set property failed when InitCollator");
61         return nullptr;
62     }
63 
64     status = napi_create_reference(env, constructor, 1, &g_constructor);
65     if (status != napi_ok || g_constructor == nullptr) {
66         HILOG_ERROR_I18N("InitCollator: napi_create_reference failed");
67         return nullptr;
68     }
69 
70     return exports;
71 }
72 
CollatorConstructor(napi_env env,napi_callback_info info)73 napi_value CollatorAddon::CollatorConstructor(napi_env env, napi_callback_info info)
74 {
75     size_t argc = 2;
76     napi_value argv[2] = { nullptr };
77     napi_value thisVar = nullptr;
78     void *data = nullptr;
79     napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
80     if (status != napi_ok) {
81         HILOG_ERROR_I18N("CollatorConstructor: napi_get_cb_info failed");
82         return nullptr;
83     }
84 
85     napi_value new_target;
86     status = napi_get_new_target(env, info, &new_target);
87     if (status == napi_pending_exception || new_target == nullptr) {
88         return CreateCollatorWithoutNew(env, argc, argv);
89     }
90 
91     std::vector<std::string> localeTags;
92     if (argc > 0) {
93         int32_t code = 0;
94         std::vector<std::string> localeArray = JSUtils::GetLocaleArray(env, argv[0], code);
95         localeTags.assign(localeArray.begin(), localeArray.end());
96     }
97     std::map<std::string, std::string> map = {};
98     if (argc > 1) {
99         GetCollatorOptionValue(env, argv[1], map);
100     }
101     CollatorAddon* obj = new(std::nothrow) CollatorAddon();
102     if (obj == nullptr) {
103         HILOG_ERROR_I18N("CollatorConstructor: make_unique CollatorAddon failed");
104         return nullptr;
105     }
106     status =
107         napi_wrap(env, thisVar, reinterpret_cast<void *>(obj), CollatorAddon::Destructor, nullptr, nullptr);
108     if (status != napi_ok) {
109         HILOG_ERROR_I18N("CollatorConstructor: Wrap CollatorAddon failed");
110         delete obj;
111         return nullptr;
112     }
113     if (!obj->InitCollatorContext(env, info, localeTags, map)) {
114         HILOG_ERROR_I18N("CollatorConstructor: Init CollatorAddon failed");
115         return nullptr;
116     }
117     return thisVar;
118 }
119 
CreateCollatorWithoutNew(napi_env env,size_t argc,napi_value * argv)120 napi_value CollatorAddon::CreateCollatorWithoutNew(napi_env env, size_t argc, napi_value *argv)
121 {
122     napi_value exception;
123     napi_status status = napi_get_and_clear_last_exception(env, &exception);
124     if (status != napi_ok) {
125         HILOG_ERROR_I18N("CreateCollatorWithoutNew: napi_get_and_clear_last_exception failed");
126         return nullptr;
127     }
128 
129     napi_value constructor = nullptr;
130     status = napi_get_reference_value(env, g_constructor, &constructor);
131     if (status != napi_ok || constructor == nullptr) {
132         HILOG_ERROR_I18N("CreateCollatorWithoutNew: napi_get_reference_value failed");
133         return nullptr;
134     }
135 
136     napi_value instance = nullptr;
137     status = napi_new_instance(env, constructor, argc, argv, &instance);
138     if (status != napi_ok || instance == nullptr) {
139         HILOG_ERROR_I18N("CreateCollatorWithoutNew: napi_new_instance failed");
140         return nullptr;
141     }
142     return instance;
143 }
144 
InitCollatorContext(napi_env env,napi_callback_info info,std::vector<std::string> localeTags,std::map<std::string,std::string> & map)145 bool CollatorAddon::InitCollatorContext(napi_env env, napi_callback_info info, std::vector<std::string> localeTags,
146     std::map<std::string, std::string> &map)
147 {
148     env_ = env;
149     collator_ = std::make_unique<Collator>(localeTags, map, "en-US");
150     if (collator_ == nullptr) {
151         HILOG_ERROR_I18N("CollatorAddon: CollatorConstructor make_unique Collator failed");
152         return false;
153     }
154     I18nErrorCode errorCode = collator_->GetError();
155     if (errorCode == I18nErrorCode::INVALID_PARAM) {
156         HILOG_ERROR_I18N("CollatorAddon: CollatorConstructor invalid param");
157         ErrorUtil::NapiThrowUndefined(env, "getStringOption failed");
158         return false;
159     } else if (errorCode == I18nErrorCode::INVALID_LOCALE_TAG) {
160         HILOG_ERROR_I18N("CollatorAddon: CollatorConstructor invalid locale");
161         ErrorUtil::NapiThrowUndefined(env, "invalid locale");
162         return false;
163     }
164     return errorCode == I18nErrorCode::SUCCESS;
165 }
166 
SupportedLocalesOf(napi_env env,napi_callback_info info)167 napi_value CollatorAddon::SupportedLocalesOf(napi_env env, napi_callback_info info)
168 {
169     size_t argc = 2;
170     napi_value argv[2] = { nullptr };
171     napi_value thisVar = nullptr;
172     void *data = nullptr;
173     std::vector<std::string> resultLocales = {};
174     napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
175     if (status != napi_ok) {
176         HILOG_ERROR_I18N("SupportedLocalesOf: napi get callback info failed.");
177         return JSUtils::CreateArray(env, resultLocales);
178     }
179     std::vector<std::string> localeTags;
180     if (argc > 0) {
181         int32_t code = 0;
182         std::vector<std::string> localeArray = JSUtils::GetLocaleArray(env, argv[0], code);
183         localeTags.assign(localeArray.begin(), localeArray.end());
184     }
185     std::map<std::string, std::string> map = {};
186     if (argc > 1) {
187         GetCollatorOptionValue(env, argv[1], map);
188     }
189     I18nErrorCode i18nStatus = I18nErrorCode::SUCCESS;
190     resultLocales = Collator::SupportedLocalesOf(localeTags, map, i18nStatus);
191     if (i18nStatus == I18nErrorCode::INVALID_PARAM) {
192         HILOG_ERROR_I18N("SupportedLocalesOf: SupportedLocalesOf invalid param");
193         ErrorUtil::NapiThrowUndefined(env, "getStringOption failed");
194     } else if (i18nStatus == I18nErrorCode::INVALID_LOCALE_TAG) {
195         HILOG_ERROR_I18N("SupportedLocalesOf: SupportedLocalesOf invalid locale");
196         ErrorUtil::NapiThrowUndefined(env, "invalid locale");
197     }
198     return JSUtils::CreateArray(env, resultLocales);
199 }
200 
CompareString(napi_env env,napi_callback_info info)201 napi_value CollatorAddon::CompareString(napi_env env, napi_callback_info info)
202 {
203     size_t argc = 2;
204     napi_value argv[2] = { 0 };
205     napi_value thisVar = nullptr;
206     void *data = nullptr;
207     napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
208     if (status != napi_ok) {
209         return nullptr;
210     }
211     std::vector<char> first;
212     if (!GetStringParameter(env, argv[0], first)) {
213         return nullptr;
214     }
215 
216     std::vector<char> second;
217     if (!GetStringParameter(env, argv[1], second)) {
218         return nullptr;
219     }
220 
221     CollatorAddon *obj = nullptr;
222     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
223     if (status != napi_ok || !obj || !obj->collator_) {
224         HILOG_ERROR_I18N("CompareString: Get Collator object failed");
225         return nullptr;
226     }
227 
228     CompareResult compareResult = obj->collator_->Compare(first.data(), second.data());
229     napi_value result = nullptr;
230     status = napi_create_int32(env, compareResult, &result);
231     if (status != napi_ok) {
232         HILOG_ERROR_I18N("CompareString: Create compare result failed");
233         return nullptr;
234     }
235 
236     return result;
237 }
238 
GetCollatorResolvedOptions(napi_env env,napi_callback_info info)239 napi_value CollatorAddon::GetCollatorResolvedOptions(napi_env env, napi_callback_info info)
240 {
241     napi_value thisVar = nullptr;
242     void *data = nullptr;
243     napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
244     if (status != napi_ok) {
245         return JSUtils::CreateEmptyObject(env);
246     }
247     CollatorAddon *obj = nullptr;
248     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
249     if (status != napi_ok || !obj || !obj->collator_) {
250         HILOG_ERROR_I18N("GetCollatorResolvedOptions: Get Collator object failed");
251         return JSUtils::CreateEmptyObject(env);
252     }
253     napi_value result = nullptr;
254     status = napi_create_object(env, &result);
255     if (status != napi_ok) {
256         return JSUtils::CreateEmptyObject(env);
257     }
258     std::map<std::string, std::string> options = {};
259     obj->collator_->ResolvedOptions(options);
260     JSUtils::SetOptionProperties(env, result, options, "localeMatcher");
261     JSUtils::SetOptionProperties(env, result, options, "locale");
262     JSUtils::SetOptionProperties(env, result, options, "usage");
263     JSUtils::SetOptionProperties(env, result, options, "sensitivity");
264     JSUtils::SetBooleanOptionProperties(env, result, options, "ignorePunctuation");
265     JSUtils::SetBooleanOptionProperties(env, result, options, "numeric");
266     JSUtils::SetOptionProperties(env, result, options, "caseFirst");
267     JSUtils::SetOptionProperties(env, result, options, "collation");
268     return result;
269 }
270 } // namespace I18n
271 } // namespace Global
272 } // namespace OHOS