• 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 #ifndef ANI_UTILS_H
16 #define ANI_UTILS_H
17 
18 #include <ani.h>
19 
20 #include <cstdarg>
21 #include <memory>
22 #include <mutex>
23 #include <optional>
24 #include <string>
25 #include <unordered_map>
26 #include <vector>
27 #include <iostream>
28 
29 class AniObjectUtils {
30 public:
31     // 创建一个ani_object对象,使用命名空间和类名
Create(ani_env * env,const char * nsName,const char * clsName,...)32     static ani_object Create(ani_env *env, const char* nsName, const char* clsName, ...)
33     {
34         // 创建一个空的对象
35         ani_object nullobj{};
36 
37         // 查找命名空间
38         ani_namespace ns;
39         if (ANI_OK != env->FindNamespace(nsName, &ns)) {
40             return nullobj;
41         }
42 
43         // 查找类
44         ani_class cls;
45         if (ANI_OK != env->Namespace_FindClass(ns, clsName, &cls)) {
46             return nullobj;
47         }
48 
49         ani_method ctor;
50         if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", nullptr, &ctor)) {
51             return nullobj;
52         }
53 
54         ani_object obj;
55         va_list args;
56         va_start(args, clsName);
57         ani_status status = env->Object_New_V(cls, ctor, &obj, args);
58         va_end(args);
59         if (ANI_OK != status)  {
60             return nullobj;
61         }
62         return obj;
63     }
64 
Create(ani_env * env,const char * clsName,...)65     static ani_object Create(ani_env *env, const char* clsName, ...)
66     {
67         ani_object nullobj{};
68         // 查找类
69         ani_class cls;
70         if (ANI_OK != env->FindClass(clsName, &cls)) {
71             return nullobj;
72         }
73         ani_method ctor;
74         if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", nullptr, &ctor)) {
75             return nullobj;
76         }
77 
78         ani_object obj;
79         va_list args;
80         va_start(args, clsName);
81         ani_status status = env->Object_New_V(cls, ctor, &obj, args);
82         va_end(args);
83         if (ANI_OK != status) {
84             return nullobj;
85         }
86         return obj;
87     }
88 
Create(ani_env * env,ani_class cls,...)89     static ani_object Create(ani_env *env, ani_class cls, ...)
90     {
91         ani_object nullobj{};
92 
93         ani_method ctor;
94         if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", nullptr, &ctor)) {
95             return nullobj;
96         }
97 
98         ani_object obj;
99         va_list args;
100         va_start(args, cls);
101         ani_status status = env->Object_New_V(cls, ctor, &obj, args);
102         va_end(args);
103         if (ANI_OK != status) {
104             return nullobj;
105         }
106         return obj;
107     }
108 
From(ani_env * env,bool value)109     static ani_object From(ani_env *env, bool value)
110     {
111         return Create(env, "Lstd/core/Boolean;", static_cast<ani_boolean>(value));
112     }
113 
114     template<typename T>
115     static ani_status Wrap(ani_env *env, ani_object object, T* nativePtr, const char* propName = "nativePtr")
116     {
117         return env->Object_SetFieldByName_Long(object, propName, reinterpret_cast<ani_long>(nativePtr));
118     }
119 
120     template<typename T>
121     static T* Unwrap(ani_env *env, ani_object object, const char* propName = "nativePtr")
122     {
123         ani_long nativePtr;
124         if (ANI_OK != env->Object_GetFieldByName_Long(object, propName, &nativePtr)) {
125             return nullptr;
126         }
127         if (nativePtr == 0) {
128             return nullptr;
129         }
130         return reinterpret_cast<T*>(nativePtr);
131     }
132 };
133 
134 class AniStringUtils {
135 public:
ToStd(ani_env * env,ani_string ani_str)136     static std::string ToStd(ani_env *env, ani_string ani_str)
137     {
138         ani_size strSize;
139         env->String_GetUTF8Size(ani_str, &strSize);
140 
141         std::vector<char> buffer(strSize + 1); // +1 for null terminator
142         char* utf8_buffer = buffer.data();
143 
144         ani_size bytes_written = 0;
145         env->String_GetUTF8(ani_str, utf8_buffer, strSize + 1, &bytes_written);
146 
147         utf8_buffer[bytes_written] = '\0';
148         std::string content = std::string(utf8_buffer);
149         return content;
150     }
151 
ToAni(ani_env * env,const std::string & str)152     static ani_string ToAni(ani_env* env, const std::string& str)
153     {
154         ani_string aniStr = nullptr;
155         if (ANI_OK != env->String_NewUTF8(str.data(), str.size(), &aniStr)) {
156             return nullptr;
157         }
158         return aniStr;
159     }
160 };
161 
162 class UnionAccessor {
163 public:
UnionAccessor(ani_env * env,ani_object & obj)164     UnionAccessor(ani_env *env, ani_object &obj) : env_(env), obj_(obj)
165     {
166     }
167 
IsInstanceOf(const std::string & cls_name)168     bool IsInstanceOf(const std::string& cls_name)
169     {
170         ani_class cls;
171         env_->FindClass(cls_name.c_str(), &cls);
172 
173         ani_boolean ret;
174         env_->Object_InstanceOf(obj_, cls, &ret);
175         return ret;
176     }
177 
178     template<typename T>
179     bool IsInstanceOfType();
180 
181     template<typename T>
182     bool TryConvert(T &value);
183 
184     template<typename T>
185     bool TryConvertArray(std::vector<T> &value);
186 
187 private:
188     ani_env *env_;
189     ani_object obj_;
190 };
191 
192 template<>
193 bool UnionAccessor::IsInstanceOfType<bool>()
194 {
195     return IsInstanceOf("Lstd/core/Boolean;");
196 }
197 
198 template<>
199 bool UnionAccessor::IsInstanceOfType<int>()
200 {
201     return IsInstanceOf("Lstd/core/Int;");
202 }
203 
204 template<>
205 bool UnionAccessor::IsInstanceOfType<double>()
206 {
207     return IsInstanceOf("Lstd/core/Double;");
208 }
209 
210 template<>
211 bool UnionAccessor::IsInstanceOfType<std::string>()
212 {
213     return IsInstanceOf("Lstd/core/String;");
214 }
215 
216 template<>
217 bool UnionAccessor::TryConvert<bool>(bool &value)
218 {
219     if (!IsInstanceOfType<bool>()) {
220         return false;
221     }
222 
223     ani_boolean aniValue;
224     auto ret = env_->Object_CallMethodByName_Boolean(obj_, "unboxed", nullptr, &aniValue);
225     if (ret != ANI_OK) {
226         return false;
227     }
228     value = static_cast<bool>(aniValue);
229     return true;
230 }
231 
232 template<>
233 bool UnionAccessor::TryConvert<int>(int &value)
234 {
235     if (!IsInstanceOfType<int>()) {
236         return false;
237     }
238 
239     ani_int aniValue;
240     auto ret = env_->Object_CallMethodByName_Int(obj_, "unboxed", nullptr, &aniValue);
241     if (ret != ANI_OK) {
242         return false;
243     }
244     value = static_cast<int>(aniValue);
245     return true;
246 }
247 
248 template<>
249 bool UnionAccessor::TryConvert<double>(double &value)
250 {
251     if (!IsInstanceOfType<double>()) {
252         return false;
253     }
254 
255     ani_double aniValue;
256     auto ret = env_->Object_CallMethodByName_Double(obj_, "unboxed", nullptr, &aniValue);
257     if (ret != ANI_OK) {
258         return false;
259     }
260     value = static_cast<double>(aniValue);
261     return true;
262 }
263 
264 template<>
265 bool UnionAccessor::TryConvert<std::string>(std::string &value)
266 {
267     if (!IsInstanceOfType<std::string>()) {
268         return false;
269     }
270 
271     value = AniStringUtils::ToStd(env_, static_cast<ani_string>(obj_));
272     return true;
273 }
274 
275 template<>
276 bool UnionAccessor::TryConvertArray<bool>(std::vector<bool> &value)
277 {
278     ani_double length;
279     if (ANI_OK != env_->Object_GetPropertyByName_Double(obj_, "length", &length)) {
280         return false;
281     }
282     for (int i = 0; i < int(length); i++) {
283         ani_ref ref;
284         if (ANI_OK != env_->Object_CallMethodByName_Ref(obj_, "$_get", "I:Lstd/core/Object;", &ref, (ani_int)i)) {
285             return false;
286         }
287         ani_boolean val;
288         if (ANI_OK != env_->Object_CallMethodByName_Boolean(static_cast<ani_object>(ref), "unboxed", nullptr, &val)) {
289             return false;
290         }
291         value.push_back(static_cast<bool>(val));
292     }
293     return true;
294 }
295 
296 template<>
297 bool UnionAccessor::TryConvertArray<int>(std::vector<int> &value)
298 {
299     ani_double length;
300     if (ANI_OK != env_->Object_GetPropertyByName_Double(obj_, "length", &length)) {
301         return false;
302     }
303     for (int i = 0; i < int(length); i++) {
304         ani_ref ref;
305         if (ANI_OK != env_->Object_CallMethodByName_Ref(obj_, "$_get", "I:Lstd/core/Object;", &ref, (ani_int)i)) {
306             return false;
307         }
308         ani_int intValue;
309         if (ANI_OK != env_->Object_CallMethodByName_Int(static_cast<ani_object>(ref), "unboxed", nullptr, &intValue)) {
310             return false;
311         }
312         value.push_back(static_cast<int>(intValue));
313     }
314     return true;
315 }
316 
317 template<>
318 bool UnionAccessor::TryConvertArray<double>(std::vector<double> &value)
319 {
320     ani_double length;
321     if (ANI_OK != env_->Object_GetPropertyByName_Double(obj_, "length", &length)) {
322         return false;
323     }
324     for (int i = 0; i < int(length); i++) {
325         ani_ref ref;
326         if (ANI_OK != env_->Object_CallMethodByName_Ref(obj_, "$_get", "I:Lstd/core/Object;", &ref, (ani_int)i)) {
327             return false;
328         }
329         ani_double val;
330         if (ANI_OK != env_->Object_CallMethodByName_Double(static_cast<ani_object>(ref), "unboxed", nullptr, &val)) {
331             return false;
332         }
333         value.push_back(static_cast<double>(val));
334     }
335     return true;
336 }
337 
338 template<>
339 bool UnionAccessor::TryConvertArray<uint8_t>(std::vector<uint8_t> &value)
340 {
341     ani_ref buffer;
342     if (ANI_OK != env_->Object_GetFieldByName_Ref(obj_, "buffer", &buffer)) {
343         return false;
344     }
345     void* data;
346     size_t length;
347     if (ANI_OK != env_->ArrayBuffer_GetInfo(static_cast<ani_arraybuffer>(buffer), &data, &length)) {
348         return false;
349     }
350 
351     for (size_t i = 0; i < length; i++) {
352         value.push_back(static_cast<uint8_t*>(data)[i]);
353     }
354     return true;
355 }
356 
357 template<>
358 bool UnionAccessor::TryConvertArray<std::string>(std::vector<std::string> &value)
359 {
360     ani_double length;
361     if (ANI_OK != env_->Object_GetPropertyByName_Double(obj_, "length", &length)) {
362         return false;
363     }
364 
365     for (int i = 0; i < int(length); i++) {
366         ani_ref ref;
367         if (ANI_OK != env_->Object_CallMethodByName_Ref(obj_, "$_get", "I:Lstd/core/Object;", &ref, (ani_int)i)) {
368             return false;
369         }
370         value.push_back(AniStringUtils::ToStd(env_, static_cast<ani_string>(ref)));
371     }
372     return true;
373 }
374 
375 class OptionalAccessor {
376 public:
OptionalAccessor(ani_env * env,ani_object & obj)377     OptionalAccessor(ani_env *env, ani_object &obj) : env_(env), obj_(obj)
378     {
379     }
380 
IsUndefined()381     bool IsUndefined()
382     {
383         ani_boolean isUndefined;
384         env_->Reference_IsUndefined(obj_, &isUndefined);
385         return isUndefined;
386     }
387 
388     template<typename T>
389     std::optional<T> Convert();
390 
391 private:
392     ani_env *env_;
393     ani_object obj_;
394 };
395 
396 template<>
397 std::optional<double> OptionalAccessor::Convert<double>()
398 {
399     if (IsUndefined()) {
400         return std::nullopt;
401     }
402 
403     ani_double aniValue;
404     auto ret = env_->Object_CallMethodByName_Double(obj_, "doubleValue", nullptr, &aniValue);
405     if (ret != ANI_OK) {
406         return std::nullopt;
407     }
408     auto value = static_cast<double>(aniValue);
409     return value;
410 }
411 
412 template<>
413 std::optional<std::string> OptionalAccessor::Convert<std::string>()
414 {
415     if (IsUndefined()) {
416         return std::nullopt;
417     }
418 
419     ani_size strSize;
420     env_->String_GetUTF8Size(static_cast<ani_string>(obj_), &strSize);
421 
422     std::vector<char> buffer(strSize + 1);
423     char* utf8_buffer = buffer.data();
424 
425     ani_size bytes_written = 0;
426     env_->String_GetUTF8(static_cast<ani_string>(obj_), utf8_buffer, strSize + 1, &bytes_written);
427 
428     utf8_buffer[bytes_written] = '\0';
429     std::string content = std::string(utf8_buffer);
430     return content;
431 }
432 
433 
434 class EnumAccessor {
435 public:
EnumAccessor(ani_env * env,const char * className,ani_int index)436     EnumAccessor(ani_env *env, const char* className, ani_int index) : env_(env), className_(className), index_(index)
437     {
438     }
439 
ToInt(int32_t & value)440     ani_status ToInt(int32_t &value)
441     {
442         ani_status status = ANI_ERROR;
443         ani_enum_item item;
444         status = GetItem(item);
445         if (ANI_OK != status) {
446             return status;
447         }
448 
449         status = env_->EnumItem_GetValue_Int(item, &value);
450         if (ANI_OK != status) {
451             return status;
452         }
453         return ANI_OK;
454     }
455 
ToString(std::string & value)456     ani_status ToString(std::string &value)
457     {
458         ani_status status = ANI_ERROR;
459         ani_enum_item item;
460         status = GetItem(item);
461         if (ANI_OK != status) {
462             return status;
463         }
464 
465         ani_string strValue;
466         status = env_->EnumItem_GetValue_String(item, &strValue);
467         if (ANI_OK != status) {
468             return status;
469         }
470         value = AniStringUtils::ToStd(env_, strValue);
471 
472         return ANI_OK;
473     }
474 
475 private:
GetItem(ani_enum_item & item)476     ani_status GetItem(ani_enum_item &item)
477     {
478         ani_status status = ANI_ERROR;
479         ani_enum enumType;
480         status = env_->FindEnum(className_.c_str(), &enumType);
481         if (ANI_OK != status) {
482             return status;
483         }
484 
485         status = env_->Enum_GetEnumItemByIndex(enumType, index_, &item);
486         if (ANI_OK != status) {
487             return status;
488         }
489         return ANI_OK;
490     }
491 
492 private:
493     ani_env *env_;
494     std::string className_;
495     ani_int index_;
496 };
497 #endif
498