• 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 PREFERENCES_ANI_COMMON_INCLUDE_ANI_UTILS_H
17 #define PREFERENCES_ANI_COMMON_INCLUDE_ANI_UTILS_H
18 
19 #include <ani.h>
20 
21 #include <memory>
22 #include <mutex>
23 #include <string>
24 #include <unordered_map>
25 #include <vector>
26 
27 template<typename T>
28 class NativeObjectWrapper {
29 public:
Create(ani_env * env,ani_class clazz)30     static ani_object Create([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_class clazz)
31     {
32         T* nativePtr = new (std::nothrow) T();
33         if (!nativePtr) {
34             return nullptr;
35         }
36         return Wrap(env, clazz, nativePtr);
37     }
38 
Wrap(ani_env * env,ani_class clazz,T * nativePtr)39     static ani_object Wrap([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_class clazz, T* nativePtr)
40     {
41         ani_method ctor;
42         if (ANI_OK != env->Class_FindMethod(clazz, "<ctor>", "J:V", &ctor)) {
43             return nullptr;
44         }
45 
46         ani_object obj = nullptr;
47         if (ANI_OK != env->Object_New(clazz, ctor, &obj, reinterpret_cast<ani_long>(nativePtr))) {
48             return nullptr;
49         }
50         return obj;
51     }
52 
53     static T* Unwrap(ani_env *env, ani_object object, const char* propName = "nativePtr")
54     {
55         ani_long nativePtr;
56         if (ANI_OK != env->Object_GetFieldByName_Long(object, propName, &nativePtr)) {
57             return nullptr;
58         }
59         return reinterpret_cast<T*>(nativePtr);
60     }
61 };
62 
AniStringToStdStr(ani_env * env,ani_string aniStr)63 std::string AniStringToStdStr(ani_env *env, ani_string aniStr)
64 {
65     ani_size strSize;
66     env->String_GetUTF8Size(aniStr, &strSize);
67     if (strSize == 0) {
68         return "";
69     }
70     std::vector<char> buffer(strSize + 1);
71     char* utf8Buffer = buffer.data();
72 
73     ani_size bytesWritten = 0;
74     env->String_GetUTF8(aniStr, utf8Buffer, strSize + 1, &bytesWritten);
75     if (bytesWritten > strSize) {
76         bytesWritten = strSize;
77     }
78     utf8Buffer[bytesWritten] = '\0';
79     std::string content = std::string(utf8Buffer);
80     return content;
81 }
82 
ANIUtils_UnionIsInstanceOf(ani_env * env,ani_object unionObj,std::string & clsName)83 bool ANIUtils_UnionIsInstanceOf(ani_env *env, ani_object unionObj, std::string& clsName)
84 {
85     ani_class cls;
86     env->FindClass(clsName.c_str(), &cls);
87 
88     ani_boolean ret;
89     env->Object_InstanceOf(unionObj, cls, &ret);
90     return ret;
91 }
92 
93 class UnionAccessor {
94 public:
UnionAccessor(ani_env * env,ani_object & obj)95     UnionAccessor(ani_env *env, ani_object &obj)
96         : env_(env), obj_(obj) {}
97 
IsInstanceOf(std::string && clsName)98     bool IsInstanceOf(std::string&& clsName)
99     {
100         ani_class cls;
101         env_->FindClass(clsName.c_str(), &cls);
102 
103         ani_boolean ret;
104         env_->Object_InstanceOf(obj_, cls, &ret);
105         return ret;
106     }
107 
IsInstanceOf(std::string && clsName,ani_object obj)108     bool IsInstanceOf(std::string&& clsName, ani_object obj)
109     {
110         ani_class cls;
111         env_->FindClass(clsName.c_str(), &cls);
112 
113         ani_boolean ret;
114         env_->Object_InstanceOf(obj, cls, &ret);
115         return ret;
116     }
117 
118     template<typename T>
119     bool TryConvert(T &value);
120 
121 private:
122     ani_env *env_;
123     ani_object obj_;
124 };
125 
126 template<>
127 bool UnionAccessor::TryConvert<ani_boolean>(ani_boolean &value)
128 {
129     if (!IsInstanceOf("Lstd/core/Boolean;")) {
130         return false;
131     }
132     return ANI_OK == env_->Object_CallMethodByName_Boolean(obj_, "booleanValue", nullptr, &value);
133 }
134 
135 template<>
136 bool UnionAccessor::TryConvert<ani_double>(ani_double &value)
137 {
138     if (!IsInstanceOf("Lstd/core/Double;")) {
139         return false;
140     }
141     return ANI_OK == env_->Object_CallMethodByName_Double(obj_, "unboxed", nullptr, &value);
142 }
143 
144 template<>
145 bool UnionAccessor::TryConvert<std::string>(std::string &value)
146 {
147     if (!IsInstanceOf("Lstd/core/String;")) {
148         return false;
149     }
150     value = AniStringToStdStr(env_, static_cast<ani_string>(obj_));
151     return true;
152 }
153 
154 template<>
155 bool UnionAccessor::TryConvert<ani_long>(ani_long &value)
156 {
157     if (!IsInstanceOf("Lescompat/BigInt;")) {
158         return false;
159     }
160     ani_class bigIntCls;
161     const char* className = "Lescompat/BigInt;";
162     if (ANI_OK != env_->FindClass(className, &bigIntCls)) {
163         return false;
164     }
165     ani_method getLongMethod;
166     if (ANI_OK != env_->Class_FindMethod(bigIntCls, "getLong", ":J", &getLongMethod)) {
167         return false;
168     }
169 
170     if (ANI_OK != env_->Object_CallMethod_Long(obj_, getLongMethod, &value)) {
171         return false;
172     }
173     return true;
174 }
175 
176 template<>
177 bool UnionAccessor::TryConvert<std::vector<double>>(std::vector<double> &value)
178 {
179     ani_double length;
180     if (ANI_OK != env_->Object_GetPropertyByName_Double(obj_, "length", &length)) {
181         return false;
182     }
183     if (length > static_cast<ani_double>(INT_MAX)) {
184         return false;
185     }
186     for (int i = 0; i < static_cast<int>(length); i++) {
187         ani_ref arrayRef;
188         if (ANI_OK != env_->Object_CallMethodByName_Ref(obj_, "$_get", "I:Lstd/core/Object;", &arrayRef, (ani_int)i)) {
189             return false;
190         }
191         if (!IsInstanceOf("Lstd/core/Double;", static_cast<ani_object>(arrayRef))) {
192             return false;
193         }
194         ani_double doubleValue;
195         if (ANI_OK != env_->Object_CallMethodByName_Double(static_cast<ani_object>(arrayRef), "unboxed",
196             nullptr, &doubleValue)) {
197             return false;
198         }
199         value.push_back(static_cast<double>(doubleValue));
200     }
201     return true;
202 }
203 
204 template<>
205 bool UnionAccessor::TryConvert<std::vector<std::string>>(std::vector<std::string> &value)
206 {
207     ani_double length;
208     if (ANI_OK != env_->Object_GetPropertyByName_Double(obj_, "length", &length)) {
209         return false;
210     }
211     for (int i = 0; i < int(length); i++) {
212         ani_ref arrayRef;
213         if (ANI_OK != env_->Object_CallMethodByName_Ref(obj_, "$_get", "I:Lstd/core/Object;", &arrayRef, (ani_int)i)) {
214             return false;
215         }
216         if (!IsInstanceOf("Lstd/core/String;", static_cast<ani_object>(arrayRef))) {
217             return false;
218         }
219         value.push_back(AniStringToStdStr(env_, static_cast<ani_string>(arrayRef)));
220     }
221     return true;
222 }
223 
224 template<>
225 bool UnionAccessor::TryConvert<std::vector<bool>>(std::vector<bool> &value)
226 {
227     ani_double length;
228     if (ANI_OK != env_->Object_GetPropertyByName_Double(obj_, "length", &length)) {
229         return false;
230     }
231     for (int i = 0; i < int(length); i++) {
232         ani_ref arrayRef;
233         if (ANI_OK != env_->Object_CallMethodByName_Ref(obj_, "$_get", "I:Lstd/core/Object;", &arrayRef, (ani_int)i)) {
234             return false;
235         }
236         if (!IsInstanceOf("Lstd/core/Boolean;", static_cast<ani_object>(arrayRef))) {
237             return false;
238         }
239         ani_boolean boolValue;
240         if (ANI_OK != env_->Object_CallMethodByName_Boolean(static_cast<ani_object>(arrayRef), "unboxed", nullptr,
241             &boolValue)) {
242             return false;
243         }
244         value.push_back(static_cast<bool>(boolValue));
245     }
246     return true;
247 }
248 
249 template<>
250 bool UnionAccessor::TryConvert<std::vector<uint8_t>>(std::vector<uint8_t> &value)
251 {
252     ani_ref buffer;
253     if (ANI_OK != env_->Object_GetFieldByName_Ref(obj_, "buffer", &buffer)) {
254         return false;
255     }
256     void* data;
257     size_t length;
258     if (ANI_OK != env_->ArrayBuffer_GetInfo(static_cast<ani_arraybuffer>(buffer), &data, &length)) {
259         return false;
260     }
261     for (size_t i = 0; i < length; i++) {
262         value.emplace_back(static_cast<uint8_t*>(data)[i]);
263     }
264     return true;
265 }
266 #endif // PREFERENCES_ANI_COMMON_INCLUDE_ANI_UTILS_H
267