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 "variable_converter.h"
17
18 #include "entity_recognizer_addon.h"
19 #include "holiday_manager_addon.h"
20 #include "i18n_addon.h"
21 #include "i18n_calendar_addon.h"
22 #include "i18n_hilog.h"
23 #include "i18n_normalizer_addon.h"
24 #include "i18n_timezone_addon.h"
25 #include "intl_addon.h"
26 #include "locale_info_addon.h"
27 #include "number_format_addon.h"
28 #include "simple_date_time_format_addon.h"
29 #include "simple_number_format_addon.h"
30 #include "system_locale_manager_addon.h"
31
32 using namespace OHOS;
33 using namespace Global;
34 using namespace I18n;
35
AniStrToString(ani_env * env,ani_ref aniStr)36 std::string VariableConverter::AniStrToString(ani_env *env, ani_ref aniStr)
37 {
38 ani_string ani_str = static_cast<ani_string>(aniStr);
39 ani_size strSize;
40 if (ANI_OK != env->String_GetUTF8Size(ani_str, &strSize)) {
41 HILOG_ERROR_I18N("Get utf8 size failed");
42 return "";
43 }
44
45 std::vector<char> buffer(strSize + 1);
46 ani_size bytes_written = 0;
47
48 if (ANI_OK != env->String_GetUTF8(ani_str, buffer.data(), buffer.size(), &bytes_written)) {
49 HILOG_ERROR_I18N("Create string failed");
50 return "";
51 }
52 return std::string(buffer.data(), bytes_written);
53 }
54
StringToAniStr(ani_env * env,const std::string & str)55 ani_string VariableConverter::StringToAniStr(ani_env *env, const std::string &str)
56 {
57 ani_string ret;
58 if (ANI_OK != env->String_NewUTF8(str.c_str(), str.size(), &ret)) {
59 HILOG_ERROR_I18N("Create ani string failed");
60 return nullptr;
61 }
62 return ret;
63 }
64
SetBooleanMember(ani_env * env,ani_object obj,const std::string & name,const std::string & value)65 void VariableConverter::SetBooleanMember(ani_env *env, ani_object obj,
66 const std::string &name, const std::string &value)
67 {
68 if (value.empty()) {
69 return;
70 }
71
72 static const char *className = "Lstd/core/Boolean;";
73 ani_class cls;
74 if (ANI_OK != env->FindClass(className, &cls)) {
75 HILOG_ERROR_I18N("Find class '%{public}s' failed", className);
76 return;
77 }
78
79 ani_method ctor;
80 if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", "Z:V", &ctor)) {
81 HILOG_ERROR_I18N("Find method '<ctor>' failed");
82 return;
83 }
84
85 ani_boolean valueBool = value == "true";
86 ani_object boolObj;
87 if (ANI_OK != env->Object_New(cls, ctor, &boolObj, valueBool)) {
88 HILOG_ERROR_I18N("New object '%{public}s' failed", className);
89 return;
90 }
91
92 if (ANI_OK != env->Object_SetPropertyByName_Ref(obj, name.c_str(), boolObj)) {
93 HILOG_ERROR_I18N("Set property '%{public}s' failed", name.c_str());
94 return;
95 }
96 }
97
GetBooleanMember(ani_env * env,ani_object options,const std::string & name,bool & value)98 bool VariableConverter::GetBooleanMember(ani_env *env, ani_object options, const std::string &name, bool& value)
99 {
100 ani_ref ref;
101 if (ANI_OK != env->Object_GetPropertyByName_Ref(options, name.c_str(), &ref)) {
102 HILOG_ERROR_I18N("Get property '%{public}s' failed", name.c_str());
103 return false;
104 }
105
106 ani_boolean isUndefined;
107 if (ANI_OK != env->Reference_IsUndefined(ref, &isUndefined)) {
108 HILOG_ERROR_I18N("Reference IsUndefined failed");
109 return false;
110 }
111 if (isUndefined) {
112 return false;
113 }
114
115 ani_boolean ret;
116 if (ANI_OK != env->Object_CallMethodByName_Boolean(static_cast<ani_object>(ref), "unboxed", ":Z", &ret)) {
117 HILOG_ERROR_I18N("Call method by name failed");
118 return false;
119 }
120 value = ret;
121 return true;
122 }
123
SetNumberMember(ani_env * env,ani_object obj,const std::string & name,const ani_int value)124 void VariableConverter::SetNumberMember(ani_env *env, ani_object obj, const std::string &name, const ani_int value)
125 {
126 static const char *className = "Lstd/core/Int;";
127 ani_class cls;
128 if (ANI_OK != env->FindClass(className, &cls)) {
129 HILOG_ERROR_I18N("Find class '%{public}s' failed", className);
130 return;
131 }
132
133 ani_method ctor;
134 if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", "I:V", &ctor)) {
135 HILOG_ERROR_I18N("Find method '<ctor>' failed");
136 return;
137 }
138
139 ani_object intObj;
140 if (ANI_OK != env->Object_New(cls, ctor, &intObj, value)) {
141 HILOG_ERROR_I18N("New object '%{public}s' failed", className);
142 return;
143 }
144
145 if (ANI_OK != env->Object_SetPropertyByName_Ref(obj, name.c_str(), intObj)) {
146 HILOG_ERROR_I18N("Set property '%{public}s' failed", name.c_str());
147 return;
148 }
149 }
150
SetNumberMember(ani_env * env,ani_object obj,const std::string & name,const std::string & value)151 void VariableConverter::SetNumberMember(ani_env *env, ani_object obj, const std::string &name, const std::string &value)
152 {
153 if (value.empty()) {
154 return;
155 }
156
157 static const char *className = "Lstd/core/Int;";
158 ani_class cls;
159 if (ANI_OK != env->FindClass(className, &cls)) {
160 HILOG_ERROR_I18N("Find class '%{public}s' failed", className);
161 return;
162 }
163
164 ani_method ctor;
165 if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", "I:V", &ctor)) {
166 HILOG_ERROR_I18N("Find method '<ctor>' failed");
167 return;
168 }
169
170 int32_t status = 0;
171 ani_int digits = ConvertString2Int(value, status);
172 if (status != 0) {
173 return;
174 }
175
176 ani_object intObj;
177 if (ANI_OK != env->Object_New(cls, ctor, &intObj, digits)) {
178 HILOG_ERROR_I18N("New object '%{public}s' failed", className);
179 return;
180 }
181
182 if (ANI_OK != env->Object_SetPropertyByName_Ref(obj, name.c_str(), intObj)) {
183 HILOG_ERROR_I18N("Set property '%{public}s' failed", name.c_str());
184 return;
185 }
186 }
187
GetNumberMember(ani_env * env,ani_object options,const std::string & name,int & value)188 bool VariableConverter::GetNumberMember(ani_env *env, ani_object options, const std::string &name, int& value)
189 {
190 ani_ref ref;
191 if (ANI_OK != env->Object_GetPropertyByName_Ref(options, name.c_str(), &ref)) {
192 HILOG_ERROR_I18N("Get property '%{public}s' failed", name.c_str());
193 return false;
194 }
195
196 ani_boolean isUndefined;
197 if (ANI_OK != env->Reference_IsUndefined(ref, &isUndefined)) {
198 HILOG_ERROR_I18N("Reference IsUndefined failed");
199 return false;
200 }
201 if (isUndefined) {
202 return false;
203 }
204
205 ani_double valueDouble;
206 if (ANI_OK != env->Object_CallMethodByName_Double(static_cast<ani_object>(ref), "unboxed", ":D", &valueDouble)) {
207 HILOG_ERROR_I18N("Unboxed Double failed");
208 return false;
209 }
210 value = static_cast<int>(valueDouble);
211 return true;
212 }
213
SetStringMember(ani_env * env,ani_object obj,const std::string & name,const std::string & value)214 void VariableConverter::SetStringMember(ani_env *env, ani_object obj, const std::string &name, const std::string &value)
215 {
216 if (value.empty()) {
217 return;
218 }
219
220 if (ANI_OK != env->Object_SetPropertyByName_Ref(obj, name.c_str(), VariableConverter::StringToAniStr(env, value))) {
221 HILOG_ERROR_I18N("Set property '%{public}s' failed", name.c_str());
222 return;
223 }
224 }
225
GetStringMember(ani_env * env,ani_object options,const std::string & name,std::string & value)226 bool VariableConverter::GetStringMember(ani_env *env, ani_object options, const std::string &name, std::string &value)
227 {
228 ani_ref ref;
229 if (ANI_OK != env->Object_GetPropertyByName_Ref(options, name.c_str(), &ref)) {
230 HILOG_ERROR_I18N("Get property '%{public}s' failed", name.c_str());
231 return false;
232 }
233
234 ani_boolean isUndefined;
235 if (ANI_OK != env->Reference_IsUndefined(ref, &isUndefined)) {
236 HILOG_ERROR_I18N("Reference IsUndefined failed");
237 return false;
238 }
239 if (isUndefined) {
240 return false;
241 }
242
243 value = VariableConverter::AniStrToString(env, ref);
244 return true;
245 }
246
CreateArray(ani_env * env,const std::vector<std::string> & strs)247 ani_object VariableConverter::CreateArray(ani_env *env, const std::vector<std::string> &strs)
248 {
249 static const char *className = "Lescompat/Array;";
250 ani_class cls;
251 if (ANI_OK != env->FindClass(className, &cls)) {
252 HILOG_ERROR_I18N("Find class '%{public}s' failed", className);
253 return nullptr;
254 }
255
256 ani_method ctor;
257 if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", "I:V", &ctor)) {
258 HILOG_ERROR_I18N("Find method '<ctor>' failed");
259 return nullptr;
260 }
261
262 ani_object ret;
263 if (ANI_OK != env->Object_New(cls, ctor, &ret, strs.size())) {
264 HILOG_ERROR_I18N("New object '%{public}s' failed", className);
265 return nullptr;
266 }
267
268 ani_method set;
269 if (ANI_OK != env->Class_FindMethod(cls, "$_set", "ILstd/core/Object;:V", &set)) {
270 HILOG_ERROR_I18N("Find method '$_set' failed");
271 return ret;
272 }
273
274 for (size_t i = 0; i < strs.size(); ++i) {
275 if (ANI_OK != env->Object_CallMethod_Void(ret, set, i, VariableConverter::StringToAniStr(env, strs[i]))) {
276 HILOG_ERROR_I18N("Call method '$_set' failed");
277 return ret;
278 }
279 }
280 return ret;
281 }
282
ParseStringArray(ani_env * env,ani_object obj,std::vector<std::string> & strs)283 bool VariableConverter::ParseStringArray(ani_env *env, ani_object obj, std::vector<std::string> &strs)
284 {
285 static const char *className = "Lescompat/Array;";
286 ani_class cls;
287 if (ANI_OK != env->FindClass(className, &cls)) {
288 HILOG_ERROR_I18N("Find class '%{public}s' failed", className);
289 return false;
290 }
291
292 ani_method getLengthMethod;
293 if (ANI_OK != env->Class_FindGetter(cls, "length", &getLengthMethod)) {
294 HILOG_ERROR_I18N("Find getter 'length' failed");
295 return false;
296 }
297
298 ani_double length;
299 if (ANI_OK != env->Object_CallMethod_Double(obj, getLengthMethod, &length)) {
300 HILOG_ERROR_I18N("Get 'length' failed");
301 return false;
302 }
303
304 ani_method get;
305 if (ANI_OK != env->Class_FindMethod(cls, "$_get", "I:Lstd/core/Object;", &get)) {
306 HILOG_ERROR_I18N("Find method '$_get' failed");
307 return false;
308 }
309
310 for (int i = 0; i < static_cast<int>(length); ++i) {
311 ani_ref value;
312 if (ANI_OK != env->Object_CallMethod_Ref(obj, get, &value, i)) {
313 HILOG_ERROR_I18N("Call method '$_get' failed");
314 return false;
315 }
316 strs.push_back(VariableConverter::AniStrToString(env, static_cast<ani_string>(value)));
317 }
318 return true;
319 }
320
GetEnumItemByIndex(ani_env * env,const char * enumClassName,const int index)321 ani_enum_item VariableConverter::GetEnumItemByIndex(ani_env* env, const char* enumClassName, const int index)
322 {
323 ani_enum aniEnum;
324 if (ANI_OK != env->FindEnum(enumClassName, &aniEnum)) {
325 HILOG_ERROR_I18N("Find enum '%{public}s' failed", enumClassName);
326 return nullptr;
327 }
328
329 ani_enum_item enumItem;
330 if (ANI_OK != env->Enum_GetEnumItemByIndex(aniEnum, index, &enumItem)) {
331 HILOG_ERROR_I18N("Get enumItem '%{public}s' failed", enumClassName);
332 return nullptr;
333 }
334 return enumItem;
335 }
336
GetDateValue(ani_env * env,ani_object date,const std::string & method)337 ani_double VariableConverter::GetDateValue(ani_env *env, ani_object date, const std::string &method)
338 {
339 static const char* className = "Lescompat/Date;";
340 ani_class cls;
341 if (ANI_OK != env->FindClass(className, &cls)) {
342 HILOG_ERROR_I18N("Find class '%{public}s' failed", className);
343 return -1;
344 }
345
346 ani_method get;
347 if (ANI_OK != env->Class_FindMethod(cls, method.c_str(), nullptr, &get)) {
348 HILOG_ERROR_I18N("Find method '%{public}s' failed", method.c_str());
349 return -1;
350 }
351
352 ani_double ret;
353 if (ANI_OK != env->Object_CallMethod_Double(date, get, &ret)) {
354 HILOG_ERROR_I18N("Call method '%{public}s' failed", method.c_str());
355 return -1;
356 }
357 return ret;
358 }
359
GetLocaleTags(ani_env * env,ani_object locale)360 std::vector<std::string> VariableConverter::GetLocaleTags(ani_env *env, ani_object locale)
361 {
362 std::vector<std::string> localeTags;
363 ani_class stringClass;
364 if (ANI_OK != env->FindClass("Lstd/core/String;", &stringClass)) {
365 HILOG_ERROR_I18N("Find class 'Lstd/core/String' failed");
366 return localeTags;
367 }
368
369 ani_boolean isString;
370 if (ANI_OK != env->Object_InstanceOf(locale, stringClass, &isString)) {
371 HILOG_ERROR_I18N("Get Instance failed");
372 return localeTags;
373 }
374 if (isString) {
375 localeTags.push_back(AniStrToString(env, locale));
376 return localeTags;
377 }
378 static const char *className = "Lescompat/Array;";
379 ani_class cls;
380 if (ANI_OK != env->FindClass(className, &cls)) {
381 HILOG_ERROR_I18N("Find class '%{public}s' failed", className);
382 return localeTags;
383 }
384
385 ani_method getLengthMethod;
386 if (ANI_OK != env->Class_FindGetter(cls, "length", &getLengthMethod)) {
387 HILOG_ERROR_I18N("Find getter 'length' failed");
388 return localeTags;
389 }
390
391 ani_double length;
392 if (ANI_OK != env->Object_CallMethod_Double(locale, getLengthMethod, &length)) {
393 HILOG_ERROR_I18N("Get 'length' failed");
394 return localeTags;
395 }
396
397 ani_method get;
398 if (ANI_OK != env->Class_FindMethod(cls, "$_get", "I:Lstd/core/Object;", &get)) {
399 HILOG_ERROR_I18N("Find method '$_get' failed");
400 return localeTags;
401 }
402
403 for (int i = 0; i < static_cast<int>(length); ++i) {
404 ani_ref value;
405 if (ANI_OK != env->Object_CallMethod_Ref(locale, get, &value, i)) {
406 HILOG_ERROR_I18N("Call method '$_get' failed");
407 return localeTags;
408 }
409 localeTags.push_back(AniStrToString(env, value));
410 }
411 return localeTags;
412 }
413
414 template<typename T>
CreateAniObject(ani_env * env,const char * className,T * ptr)415 ani_object VariableConverter::CreateAniObject(ani_env* env, const char* className, T* ptr)
416 {
417 ani_class cls;
418 if (ANI_OK != env->FindClass(className, &cls)) {
419 HILOG_ERROR_I18N("Find class '%{public}s' failed", className);
420 return nullptr;
421 }
422
423 ani_method ctor;
424 if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", "J:V", &ctor)) {
425 HILOG_ERROR_I18N("Find method '<ctor>' failed");
426 return nullptr;
427 }
428
429 ani_object obj;
430 if (ANI_OK != env->Object_New(cls, ctor, &obj, reinterpret_cast<ani_long>(ptr))) {
431 HILOG_ERROR_I18N("New object '%{public}s' failed", className);
432 return nullptr;
433 }
434 return obj;
435 }
436
437 template ani_object VariableConverter::CreateAniObject<I18nBreakIteratorAddon>(
438 ani_env*, const char*, I18nBreakIteratorAddon*);
439 template ani_object VariableConverter::CreateAniObject<I18nCalendarAddon>(ani_env*, const char*, I18nCalendarAddon*);
440 template ani_object VariableConverter::CreateAniObject<I18nEntityRecognizerAddon>(
441 ani_env*, const char*, I18nEntityRecognizerAddon*);
442 template ani_object VariableConverter::CreateAniObject<I18nHolidayManagerAddon>(
443 ani_env*, const char*, I18nHolidayManagerAddon*);
444 template ani_object VariableConverter::CreateAniObject<I18nIndexUtilAddon>(ani_env*, const char*, I18nIndexUtilAddon*);
445 template ani_object VariableConverter::CreateAniObject<I18nNormalizerAddon>(
446 ani_env*, const char*, I18nNormalizerAddon*);
447 template ani_object VariableConverter::CreateAniObject<I18nPhoneNumberFormatAddon>(
448 ani_env*, const char*, I18nPhoneNumberFormatAddon*);
449 template ani_object VariableConverter::CreateAniObject<I18nSimpleDateTimeFormatAddon>(
450 ani_env*, const char*, I18nSimpleDateTimeFormatAddon*);
451 template ani_object VariableConverter::CreateAniObject<I18nSimpleNumberFormatAddon>(
452 ani_env*, const char*, I18nSimpleNumberFormatAddon*);
453 template ani_object VariableConverter::CreateAniObject<I18nSysLocaleMgrAddon>(
454 ani_env*, const char*, I18nSysLocaleMgrAddon*);
455 template ani_object VariableConverter::CreateAniObject<I18nTimeZoneAddon>(ani_env*, const char*, I18nTimeZoneAddon*);
456 template ani_object VariableConverter::CreateAniObject<I18nTransliteratorAddon>(
457 ani_env*, const char*, I18nTransliteratorAddon*);
458 template ani_object VariableConverter::CreateAniObject<IntlAddon>(ani_env*, const char*, IntlAddon*);
459 template ani_object VariableConverter::CreateAniObject<LocaleInfoAddon>(ani_env*, const char*, LocaleInfoAddon*);
460 template ani_object VariableConverter::CreateAniObject<NumberFormatAddon>(ani_env*, const char*, NumberFormatAddon*);
461