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