1 /*
2 * Copyright (c) 2023-2024 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 "locale_info_addon.h"
19 #include "variable_convertor.h"
20
21 namespace OHOS {
22 namespace Global {
23 namespace I18n {
24 const std::map<napi_valuetype, std::string> VariableConvertor::NAPI_TYPE_MAP {
25 {napi_valuetype::napi_boolean, "boolean"},
26 {napi_valuetype::napi_number, "number"},
27 {napi_valuetype::napi_string, "string"},
28 {napi_valuetype::napi_bigint, "bigint"},
29 {napi_valuetype::napi_symbol, "symbol"},
30 {napi_valuetype::napi_object, "object"},
31 {napi_valuetype::napi_null, "null"},
32 {napi_valuetype::napi_undefined, "undefined"},
33 };
34
CheckNapiIsNull(napi_env env,napi_value value)35 bool VariableConvertor::CheckNapiIsNull(napi_env env, napi_value value)
36 {
37 if (value != nullptr) {
38 napi_valuetype valueType = napi_valuetype::napi_undefined;
39 napi_status status = napi_typeof(env, value, &valueType);
40 if (status != napi_ok) {
41 return false;
42 }
43 if (valueType != napi_valuetype::napi_undefined && valueType != napi_valuetype::napi_null) {
44 return true;
45 }
46 }
47 return false;
48 }
49
GetOptionValue(napi_env env,napi_value options,const std::string & optionName,std::string & value)50 void VariableConvertor::GetOptionValue(napi_env env, napi_value options, const std::string &optionName,
51 std::string &value)
52 {
53 napi_value optionValue = nullptr;
54 napi_valuetype type = napi_undefined;
55 napi_status status = napi_typeof(env, options, &type);
56 if (status != napi_ok && type != napi_object) {
57 HILOG_ERROR_I18N("GetOptionValue: Get option failed, option is not an object");
58 return;
59 }
60 bool hasProperty = false;
61 napi_status propStatus = napi_has_named_property(env, options, optionName.c_str(), &hasProperty);
62 if (propStatus == napi_ok && hasProperty) {
63 status = napi_get_named_property(env, options, optionName.c_str(), &optionValue);
64 if (status == napi_ok) {
65 size_t len;
66 status = napi_get_value_string_utf8(env, optionValue, nullptr, 0, &len);
67 if (status != napi_ok) {
68 return;
69 }
70 std::vector<char> optionBuf(len + 1);
71 status = napi_get_value_string_utf8(env, optionValue, optionBuf.data(), len + 1, &len);
72 if (status != napi_ok) {
73 HILOG_ERROR_I18N("GetOptionValue: Failed to get string item");
74 return;
75 }
76 value = optionBuf.data();
77 }
78 }
79 }
80
GetBoolOptionValue(napi_env env,napi_value & options,const std::string & optionName,bool & boolVal)81 bool VariableConvertor::GetBoolOptionValue(napi_env env, napi_value &options, const std::string &optionName,
82 bool &boolVal)
83 {
84 napi_valuetype type = napi_undefined;
85 napi_status status = napi_typeof(env, options, &type);
86 if (status != napi_ok && type != napi_object) {
87 HILOG_ERROR_I18N("option is not an object");
88 ErrorUtil::NapiThrow(env, I18N_NOT_VALID, optionName, "a valid object", true);
89 return false;
90 }
91 bool hasProperty = false;
92 status = napi_has_named_property(env, options, optionName.c_str(), &hasProperty);
93 if (status != napi_ok || !hasProperty) {
94 HILOG_INFO_I18N("option don't have property %{public}s", optionName.c_str());
95 return false;
96 }
97 napi_value optionValue = nullptr;
98 status = napi_get_named_property(env, options, optionName.c_str(), &optionValue);
99 if (status != napi_ok) {
100 HILOG_INFO_I18N("get option %{public}s failed", optionName.c_str());
101 return false;
102 }
103 status = napi_get_value_bool(env, optionValue, &boolVal);
104 if (status != napi_ok) {
105 return false;
106 }
107 return true;
108 }
109
GetDouble(napi_env env,napi_value value,int32_t & code)110 double VariableConvertor::GetDouble(napi_env env, napi_value value, int32_t &code)
111 {
112 napi_valuetype valueType = napi_valuetype::napi_undefined;
113 napi_status status = napi_typeof(env, value, &valueType);
114 if (status != napi_ok) {
115 HILOG_ERROR_I18N("VariableConvertor::GetDouble Get napi_value type failed");
116 code = 1;
117 return 0;
118 }
119 if (valueType != napi_valuetype::napi_number) {
120 HILOG_ERROR_I18N("VariableConvertor::GetDouble check napi_type_number failed");
121 code = 1;
122 return 0;
123 }
124 double result = 0;
125 status = napi_get_value_double(env, value, &result);
126 if (status != napi_ok) {
127 HILOG_ERROR_I18N("VariableConvertor::GetDouble Get double failed");
128 code = 1;
129 return 0;
130 }
131 return result;
132 }
133
GetInt(napi_env env,napi_value value,int32_t & code)134 int32_t VariableConvertor::GetInt(napi_env env, napi_value value, int32_t &code)
135 {
136 napi_valuetype valueType = napi_valuetype::napi_undefined;
137 napi_status status = napi_typeof(env, value, &valueType);
138 if (status != napi_ok) {
139 HILOG_ERROR_I18N("VariableConvertor::GetInt: Get napi_value type failed");
140 code = 1;
141 return 0;
142 }
143 if (valueType != napi_valuetype::napi_number) {
144 HILOG_ERROR_I18N("VariableConvertor::GetInt: check napi_type_number failed");
145 code = 1;
146 return 0;
147 }
148 int32_t result = 0;
149 status = napi_get_value_int32(env, value, &result);
150 if (status != napi_ok) {
151 HILOG_ERROR_I18N("VariableConvertor::GetInt: get int value failed");
152 code = 1;
153 return 0;
154 }
155 return result;
156 }
157
GetString(napi_env env,napi_value value,int32_t & code)158 std::string VariableConvertor::GetString(napi_env env, napi_value value, int32_t &code)
159 {
160 size_t len = 0;
161 napi_status status = napi_get_value_string_utf8(env, value, nullptr, 0, &len);
162 if (status != napi_ok) {
163 HILOG_ERROR_I18N("Get string failed");
164 code = 1;
165 return "";
166 }
167 std::vector<char> buf(len + 1);
168 status = napi_get_value_string_utf8(env, value, buf.data(), len + 1, &len);
169 if (status != napi_ok) {
170 HILOG_ERROR_I18N("Create string failed");
171 code = 1;
172 return "";
173 }
174 std::string result(buf.data());
175 return result;
176 }
177
GetStringArrayFromJsParam(napi_env env,napi_value & jsArray,const std::string & valueName,std::vector<std::string> & strArray)178 bool VariableConvertor::GetStringArrayFromJsParam(napi_env env, napi_value &jsArray, const std::string& valueName,
179 std::vector<std::string> &strArray)
180 {
181 if (jsArray == nullptr) {
182 ErrorUtil::NapiNotFoundError(env, I18N_NOT_FOUND, valueName, true);
183 return false;
184 }
185 bool isArray = false;
186 napi_status status = napi_is_array(env, jsArray, &isArray);
187 if (status != napi_ok) {
188 return false;
189 } else if (!isArray) {
190 ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, valueName, "an Array", true);
191 return false;
192 }
193 uint32_t arrayLength = 0;
194 status = napi_get_array_length(env, jsArray, &arrayLength);
195 if (status != napi_ok) {
196 return false;
197 }
198 napi_value element = nullptr;
199 int32_t code = 0;
200 for (uint32_t i = 0; i < arrayLength; ++i) {
201 status = napi_get_element(env, jsArray, i, &element);
202 if (status != napi_ok) {
203 return false;
204 }
205 std::string str = GetString(env, element, code);
206 if (code != 0) {
207 HILOG_ERROR_I18N("GetStringArrayFromJsParam: Failed to obtain the parameter.");
208 return false;
209 }
210 strArray.push_back(str);
211 }
212 return true;
213 }
214
CreateString(napi_env env,const std::string & str)215 napi_value VariableConvertor::CreateString(napi_env env, const std::string &str)
216 {
217 napi_value result;
218 napi_status status = napi_create_string_utf8(env, str.c_str(), NAPI_AUTO_LENGTH, &result);
219 if (status != napi_ok) {
220 HILOG_ERROR_I18N("create string js variable failed.");
221 return nullptr;
222 }
223 return result;
224 }
225
CreateNumber(napi_env env,const int32_t & num)226 napi_value VariableConvertor::CreateNumber(napi_env env, const int32_t &num)
227 {
228 napi_value result;
229 napi_status status = napi_create_int32(env, num, &result);
230 if (status != napi_ok) {
231 HILOG_ERROR_I18N("create number js variable failed.");
232 return nullptr;
233 }
234 return result;
235 }
236
VerifyType(napi_env env,const std::string & valueName,napi_valuetype napiType,napi_value argv)237 void VariableConvertor::VerifyType(napi_env env, const std::string& valueName, napi_valuetype napiType,
238 napi_value argv)
239 {
240 napi_valuetype valueType = napi_valuetype::napi_undefined;
241 napi_status status = napi_typeof(env, argv, &valueType);
242 if (status != napi_ok || valueType != napiType) {
243 auto iter = NAPI_TYPE_MAP.find(napiType);
244 std::string type = iter != NAPI_TYPE_MAP.end() ? iter->second : "";
245 ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, valueName, type, true);
246 }
247 }
248
SetEnumValue(napi_env env,napi_value enumObj,const std::string & enumName,int32_t enumVal)249 napi_status VariableConvertor::SetEnumValue(napi_env env, napi_value enumObj, const std::string& enumName,
250 int32_t enumVal)
251 {
252 napi_value name = nullptr;
253 napi_status status = napi_create_string_utf8(env, enumName.c_str(), NAPI_AUTO_LENGTH, &name);
254 if (status != napi_ok) {
255 HILOG_ERROR_I18N("VariableConvertor::SetEnumValue: create string %{public}s failed.", enumName.c_str());
256 return status;
257 }
258 napi_value value = nullptr;
259 status = napi_create_int32(env, enumVal, &value);
260 if (status != napi_ok) {
261 HILOG_ERROR_I18N("VariableConvertor::SetEnumValue: create int32 %{public}d failed.", enumVal);
262 return status;
263 }
264 status = napi_set_property(env, enumObj, name, value);
265 if (status != napi_ok) {
266 HILOG_ERROR_I18N("VariableConvertor::SetEnumValue: set property %{public}s failed.", enumName.c_str());
267 return status;
268 }
269 status = napi_set_property(env, enumObj, value, name);
270 if (status != napi_ok) {
271 HILOG_ERROR_I18N("VariableConvertor::SetEnumValue: set property %{public}d failed.", enumVal);
272 return status;
273 }
274 return napi_ok;
275 }
276
GetLocaleType(napi_env env,napi_value locale)277 LocaleType VariableConvertor::GetLocaleType(napi_env env, napi_value locale)
278 {
279 napi_valuetype valueType = napi_valuetype::napi_undefined;
280 napi_status status = napi_typeof(env, locale, &valueType);
281 if (status != napi_ok) {
282 HILOG_ERROR_I18N("VariableConvertor::GetLocaleType: Failed to get type of intlLocale.");
283 return LocaleType::INVALID;
284 } else if (valueType != napi_valuetype::napi_object) {
285 ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "locale", "Locale", true);
286 return LocaleType::INVALID;
287 }
288 bool isBuiltinsLocale = VariableConvertor::IsBuiltinsLocale(env, locale);
289 if (isBuiltinsLocale) {
290 return LocaleType::BUILTINS_LOCALE;
291 }
292 bool isLocaleInfo = LocaleInfoAddon::IsLocaleInfo(env, locale);
293 if (isLocaleInfo) {
294 return LocaleType::LOCALE_INFO;
295 }
296 ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "locale", "Locale", true);
297 return LocaleType::INVALID;
298 }
299
ParseLocaleInfo(napi_env env,napi_value localeInfo)300 std::shared_ptr<LocaleInfo> VariableConvertor::ParseLocaleInfo(napi_env env, napi_value localeInfo)
301 {
302 LocaleInfoAddon *localeInfoAddon = nullptr;
303 napi_status status = napi_unwrap(env, localeInfo, reinterpret_cast<void **>(&localeInfoAddon));
304 if (status != napi_ok) {
305 HILOG_ERROR_I18N("VariableConvertor::ParseLocaleInfo: Failed to unwrap localeInfo.");
306 return nullptr;
307 } else if (!localeInfoAddon) {
308 ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "locale", "intl.Locale", true);
309 return nullptr;
310 } else if (!localeInfoAddon->GetLocaleInfo()) {
311 ErrorUtil::NapiThrow(env, I18N_NOT_VALID, "locale", "a valid intl.Locale", true);
312 return nullptr;
313 }
314 return localeInfoAddon->GetLocaleInfo();
315 }
316
ParseBuiltinsLocale(napi_env env,napi_value builtinsLocale)317 std::string VariableConvertor::ParseBuiltinsLocale(napi_env env, napi_value builtinsLocale)
318 {
319 napi_value func = nullptr;
320 napi_status status = napi_get_named_property(env, builtinsLocale, "toString", &func);
321 if (status != napi_ok || func == nullptr) {
322 HILOG_ERROR_I18N("VariableConvertor::ParseBuiltinsLocale: Get function toString failed.");
323 return "";
324 }
325 napi_value locale = nullptr;
326 status = napi_call_function(env, builtinsLocale, func, 0, nullptr, &locale);
327 if (status != napi_ok || locale == nullptr) {
328 HILOG_ERROR_I18N("VariableConvertor::ParseBuiltinsLocale: Call function failed.");
329 return "";
330 }
331 int32_t code = 0;
332 std::string localeTag = VariableConvertor::GetString(env, locale, code);
333 if (code != 0) {
334 HILOG_ERROR_I18N("VariableConvertor::ParseBuiltinsLocale: Get string failed.");
335 return "";
336 }
337 return localeTag;
338 }
339
CreateBuiltinsLocaleObject(napi_env env,const std::string & locale)340 napi_value VariableConvertor::CreateBuiltinsLocaleObject(napi_env env, const std::string& locale)
341 {
342 napi_value param = nullptr;
343 napi_status status = napi_create_string_utf8(env, locale.c_str(), NAPI_AUTO_LENGTH, ¶m);
344 if (status != napi_ok || param == nullptr) {
345 HILOG_ERROR_I18N("VariableConvertor::CreateBuiltinsLocaleObject: Create string failed.");
346 return nullptr;
347 }
348
349 napi_value localeConstructor = VariableConvertor::GetBuiltinsLocaleConstructor(env);
350 if (localeConstructor == nullptr) {
351 HILOG_ERROR_I18N("VariableConvertor::CreateBuiltinsLocaleObject: Get constructor failed.");
352 return nullptr;
353 }
354
355 size_t argc = 1;
356 napi_value argv[1] = { param };
357 napi_value builtinsLocale = nullptr;
358 status = napi_new_instance(env, localeConstructor, argc, argv, &builtinsLocale);
359 if (status != napi_ok || builtinsLocale == nullptr) {
360 HILOG_ERROR_I18N("VariableConvertor::CreateBuiltinsLocaleObject: Create locale failed.");
361 return nullptr;
362 }
363 return builtinsLocale;
364 }
365
CreateMap(napi_env env,std::unordered_map<std::string,std::string> & ump)366 napi_value VariableConvertor::CreateMap(napi_env env, std::unordered_map<std::string, std::string>& ump)
367 {
368 napi_value result = nullptr;
369 napi_status status = napi_create_map(env, &result);
370 if (status != napi_ok || result == nullptr) {
371 HILOG_ERROR_I18N("VariableConvertor::CreateMap: Create map failed.");
372 return nullptr;
373 }
374 for (const auto& item : ump) {
375 std::string key = item.first;
376 napi_value JSKey = nullptr;
377 status = napi_create_string_utf8(env, key.c_str(), NAPI_AUTO_LENGTH, &JSKey);
378 if (status != napi_ok || JSKey == nullptr) {
379 HILOG_ERROR_I18N("VariableConvertor::CreateMap: Create JSKey failed.");
380 return nullptr;
381 }
382 std::string value = item.second;
383 napi_value JSValue = nullptr;
384 status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &JSValue);
385 if (status != napi_ok || JSValue == nullptr) {
386 HILOG_ERROR_I18N("VariableConvertor::CreateMap: Create JSValue failed.");
387 return nullptr;
388 }
389 status = napi_map_set_property(env, result, JSKey, JSValue);
390 if (status != napi_ok) {
391 HILOG_ERROR_I18N("VariableConvertor::CreateMap: Map set property failed.");
392 return nullptr;
393 }
394 }
395 return result;
396 }
397
GetBuiltinsLocaleConstructor(napi_env env)398 napi_value VariableConvertor::GetBuiltinsLocaleConstructor(napi_env env)
399 {
400 napi_value global = nullptr;
401 napi_status status = napi_get_global(env, &global);
402 if (status != napi_ok || global == nullptr) {
403 HILOG_ERROR_I18N("VariableConvertor::GetBuiltinsLocaleConstructor: Get global failed.");
404 return nullptr;
405 }
406
407 napi_value intl = nullptr;
408 status = napi_get_named_property(env, global, "Intl", &intl);
409 if (status != napi_ok || intl == nullptr) {
410 HILOG_ERROR_I18N("VariableConvertor::GetBuiltinsLocaleConstructor: Load intl failed.");
411 return nullptr;
412 }
413
414 napi_value localeConstructor = nullptr;
415 status = napi_get_named_property(env, intl, "Locale", &localeConstructor);
416 if (status != napi_ok || localeConstructor == nullptr) {
417 HILOG_ERROR_I18N("VariableConvertor::GetBuiltinsLocaleConstructor: Get locale constructor failed.");
418 return nullptr;
419 }
420 return localeConstructor;
421 }
422
IsBuiltinsLocale(napi_env env,napi_value locale)423 bool VariableConvertor::IsBuiltinsLocale(napi_env env, napi_value locale)
424 {
425 napi_value localeConstructor = VariableConvertor::GetBuiltinsLocaleConstructor(env);
426 if (localeConstructor == nullptr) {
427 HILOG_ERROR_I18N("VariableConvertor::IsBuiltinsLocale: Get constructor failed.");
428 return false;
429 }
430
431 bool isBuiltinsLocale = false;
432 napi_status status = napi_instanceof(env, locale, localeConstructor, &isBuiltinsLocale);
433 if (status != napi_ok) {
434 HILOG_ERROR_I18N("VariableConvertor::IsBuiltinsLocale: Get instance of locale failed.");
435 return false;
436 }
437 return isBuiltinsLocale;
438 }
439 } // namespace I18n
440 } // namespace Global
441 } // namespace OHOS