1 /*
2  * Copyright (c) 2023 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 "error_util.h"
17 #include "i18n_hilog.h"
18 #include "js_utils.h"
19 #include "locale_config.h"
20 #include "variable_convertor.h"
21 #include "i18n_normalizer_addon.h"
22 
23 namespace OHOS {
24 namespace Global {
25 namespace I18n {
26 static thread_local napi_ref* g_normalizerConstructor = nullptr;
27 
28 const char *I18nNormalizerAddon::NORMALIZER_MODE_NFC_NAME = "NFC";
29 const char *I18nNormalizerAddon::NORMALIZER_MODE_NFD_NAME = "NFD";
30 const char *I18nNormalizerAddon::NORMALIZER_MODE_NFKC_NAME = "NFKC";
31 const char *I18nNormalizerAddon::NORMALIZER_MODE_NFKD_NAME = "NFKD";
32 
I18nNormalizerAddon()33 I18nNormalizerAddon::I18nNormalizerAddon() {}
~I18nNormalizerAddon()34 I18nNormalizerAddon::~I18nNormalizerAddon()
35 {
36 }
37 
Destructor(napi_env env,void * nativeObject,void * hint)38 void I18nNormalizerAddon::Destructor(napi_env env, void *nativeObject, void *hint)
39 {
40     if (!nativeObject) {
41         return;
42     }
43     delete reinterpret_cast<I18nNormalizerAddon *>(nativeObject);
44     nativeObject = nullptr;
45 }
46 
InitI18nNormalizer(napi_env env,napi_value exports)47 napi_value I18nNormalizerAddon::InitI18nNormalizer(napi_env env, napi_value exports)
48 {
49     napi_property_descriptor properties[] = {
50         DECLARE_NAPI_FUNCTION("normalize", Normalize),
51     };
52     napi_value constructor = nullptr;
53     napi_status status = napi_define_class(env, "Normalizer", NAPI_AUTO_LENGTH, I18nNormalizerConstructor, nullptr,
54         sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
55     if (status != napi_ok) {
56         HILOG_ERROR_I18N("InitI18nNormalizer: Failed to define class Normalizer at Init");
57         return nullptr;
58     }
59     exports = I18nNormalizerAddon::InitNormalizer(env, exports);
60     g_normalizerConstructor = new (std::nothrow) napi_ref;
61     if (!g_normalizerConstructor) {
62         HILOG_ERROR_I18N("InitI18nNormalizer: Failed to create Normalizer ref at init");
63         return nullptr;
64     }
65     status = napi_create_reference(env, constructor, 1, g_normalizerConstructor);
66     if (status != napi_ok) {
67         HILOG_ERROR_I18N("InitI18nNormalizer: Failed to create reference g_normalizerConstructor at init.");
68         return nullptr;
69     }
70     return exports;
71 }
72 
InitNormalizer(napi_env env,napi_value exports)73 napi_value I18nNormalizerAddon::InitNormalizer(napi_env env, napi_value exports)
74 {
75     napi_property_descriptor properties[] = {
76         DECLARE_NAPI_STATIC_FUNCTION("getInstance", GetI18nNormalizerInstance)
77     };
78     napi_value constructor = nullptr;
79     napi_status status = napi_define_class(env, "I18nNormalizer", NAPI_AUTO_LENGTH, JSUtils::DefaultConstructor,
80         nullptr, sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
81     if (status != napi_ok) {
82         HILOG_ERROR_I18N("InitNormalizer: Failed to define class Normalizer.");
83         return nullptr;
84     }
85     status = napi_set_named_property(env, exports, "Normalizer", constructor);
86     if (status != napi_ok) {
87         HILOG_ERROR_I18N("InitNormalizer: Set property failed When InitNormalizer.");
88         return nullptr;
89     }
90     return exports;
91 }
92 
I18nNormalizerConstructor(napi_env env,napi_callback_info info)93 napi_value I18nNormalizerAddon::I18nNormalizerConstructor(napi_env env, napi_callback_info info)
94 {
95     size_t argc = 1;
96     napi_value argv[1] = { nullptr };
97     napi_value thisVar = nullptr;
98     void *data = nullptr;
99     napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
100     if (status != napi_ok) {
101         return nullptr;
102     }
103     if (argc < 1) {
104         ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "mode", "", true);
105         return nullptr;
106     }
107     napi_valuetype valueType = napi_valuetype::napi_undefined;
108     napi_typeof(env, argv[0], &valueType);
109 
110     if (valueType != napi_valuetype::napi_number) {
111         ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "mode", "number", true);
112         return nullptr;
113     }
114     int32_t normalizerMode;
115     status = napi_get_value_int32(env, argv[0], &normalizerMode);
116     if (status != napi_ok) {
117         return nullptr;
118     }
119     if (normalizerMode != NORMALIZER_MODE_NFC && normalizerMode != NORMALIZER_MODE_NFD &&
120         normalizerMode != NORMALIZER_MODE_NFKC && normalizerMode != NORMALIZER_MODE_NFKD) {
121         ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "mode", "a valid mode", true);
122         return nullptr;
123     }
124 
125     std::unique_ptr<I18nNormalizerAddon> obj = std::make_unique<I18nNormalizerAddon>();
126     status =
127         napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()), I18nNormalizerAddon::Destructor, nullptr, nullptr);
128     if (status != napi_ok) {
129         return nullptr;
130     }
131     I18nNormalizerMode mode = I18nNormalizerMode(normalizerMode);
132     I18nErrorCode errorCode = I18nErrorCode::SUCCESS;
133     obj->normalizer_ = std::make_unique<I18nNormalizer>(mode, errorCode);
134     if (errorCode != I18nErrorCode::SUCCESS || !obj->normalizer_) {
135         return nullptr;
136     }
137     obj.release();
138     return thisVar;
139 }
140 
Normalize(napi_env env,napi_callback_info info)141 napi_value I18nNormalizerAddon::Normalize(napi_env env, napi_callback_info info)
142 {
143     size_t argc = 1;
144     napi_value argv[1] = { nullptr };
145     napi_value thisVar = nullptr;
146     void *data = nullptr;
147     napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
148     if (status != napi_ok) {
149         return nullptr;
150     }
151     if (argc < 1) {
152         ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "text", "", true);
153         return nullptr;
154     }
155     napi_valuetype valueType = napi_valuetype::napi_undefined;
156     napi_typeof(env, argv[0], &valueType);
157     if (valueType != napi_valuetype::napi_string) {
158         HILOG_ERROR_I18N("Invalid parameter type");
159         ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "text", "string", true);
160         return nullptr;
161     }
162     int32_t code = 0;
163     std::string text = VariableConvertor::GetString(env, argv[0], code);
164     if (code != 0) {
165         return nullptr;
166     }
167 
168     I18nNormalizerAddon *obj = nullptr;
169     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
170     if (status != napi_ok || obj == nullptr || obj->normalizer_ == nullptr) {
171         HILOG_ERROR_I18N("Get Normalizer object failed");
172         return nullptr;
173     }
174     I18nErrorCode errorCode = I18nErrorCode::SUCCESS;
175     std::string normalizedText = obj->normalizer_->Normalize(text.c_str(), static_cast<int32_t>(text.length()),
176         errorCode);
177     if (errorCode != I18nErrorCode::SUCCESS) {
178         return nullptr;
179     }
180     napi_value result = nullptr;
181     status = napi_create_string_utf8(env, normalizedText.c_str(), NAPI_AUTO_LENGTH, &result);
182     if (status != napi_ok) {
183         HILOG_ERROR_I18N("Create result failed");
184         return nullptr;
185     }
186     return result;
187 }
188 
SetEnumValue(napi_env env,napi_value enumObj,const char * enumName,int32_t enumVal)189 napi_status I18nNormalizerAddon::SetEnumValue(napi_env env, napi_value enumObj, const char* enumName, int32_t enumVal)
190 {
191     napi_value name = nullptr;
192     napi_status status = napi_create_string_utf8(env, enumName, NAPI_AUTO_LENGTH, &name);
193     if (status != napi_ok) {
194         return status;
195     }
196     napi_value value = nullptr;
197     status = napi_create_int32(env, enumVal, &value);
198     if (status != napi_ok) {
199         return status;
200     }
201     status = napi_set_property(env, enumObj, name, value);
202     if (status != napi_ok) {
203         return status;
204     }
205     status = napi_set_property(env, enumObj, value, name);
206     if (status != napi_ok) {
207         return status;
208     }
209     return napi_ok;
210 }
211 
CreateI18NNormalizerModeEnum(napi_env env,napi_status & initStatus)212 napi_value I18nNormalizerAddon::CreateI18NNormalizerModeEnum(napi_env env, napi_status &initStatus)
213 {
214     napi_value i18nNormalizerModel = nullptr;
215     napi_status status = napi_create_object(env, &i18nNormalizerModel);
216     if (status != napi_ok) {
217         initStatus = napi_generic_failure;
218         return nullptr;
219     }
220     status = SetEnumValue(env, i18nNormalizerModel, NORMALIZER_MODE_NFC_NAME, NORMALIZER_MODE_NFC);
221     if (status != napi_ok) {
222         initStatus = napi_generic_failure;
223         return nullptr;
224     }
225     status = SetEnumValue(env, i18nNormalizerModel, NORMALIZER_MODE_NFD_NAME, NORMALIZER_MODE_NFD);
226     if (status != napi_ok) {
227         initStatus = napi_generic_failure;
228         return nullptr;
229     }
230     status = SetEnumValue(env, i18nNormalizerModel, NORMALIZER_MODE_NFKC_NAME, NORMALIZER_MODE_NFKC);
231     if (status != napi_ok) {
232         initStatus = napi_generic_failure;
233         return nullptr;
234     }
235     status = SetEnumValue(env, i18nNormalizerModel, NORMALIZER_MODE_NFKD_NAME, NORMALIZER_MODE_NFKD);
236     if (status != napi_ok) {
237         initStatus = napi_generic_failure;
238         return nullptr;
239     }
240     return i18nNormalizerModel;
241 }
242 
GetI18nNormalizerInstance(napi_env env,napi_callback_info info)243 napi_value I18nNormalizerAddon::GetI18nNormalizerInstance(napi_env env, napi_callback_info info)
244 {
245     size_t argc = 1;
246     napi_value argv[1] = { nullptr };
247     napi_value thisVar = nullptr;
248     void *data = nullptr;
249     napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
250     if (status != napi_ok) {
251         HILOG_ERROR_I18N("Failed to get parameter of Normalizer.createInstance");
252         return nullptr;
253     }
254 
255     napi_value constructor = nullptr;
256     status = napi_get_reference_value(env, *g_normalizerConstructor, &constructor);
257     if (status != napi_ok) {
258         HILOG_ERROR_I18N("Failed to create reference of normalizer Constructor");
259         return nullptr;
260     }
261 
262     napi_value result = nullptr;
263     status = napi_new_instance(env, constructor, argc, argv, &result);
264     if (status != napi_ok) {
265         HILOG_ERROR_I18N("create normalizer instance failed");
266         return nullptr;
267     }
268     return result;
269 }
270 } // namespace I18n
271 } // namespace Global
272 } // namespace OHOS