• 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_PASTEBOARD_UTILS_H
17 #define ANI_PASTEBOARD_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         if (env == nullptr) {
33             return nullptr;
34         }
35         T* nativePtr = new T;
36         ani_object obj = Wrap(env, clazz, nativePtr);
37         if (obj == nullptr) {
38             delete nativePtr;
39             return nullptr;
40         }
41         return obj;
42     }
43 
Wrap(ani_env * env,ani_class clazz,T * nativePtr)44     static ani_object Wrap([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_class clazz, T* nativePtr)
45     {
46         if (env == nullptr || nativePtr == nullptr) {
47             return nullptr;
48         }
49         ani_method ctor;
50         if (ANI_OK != env->Class_FindMethod(clazz, "<ctor>", "J:V", &ctor)) {
51             ani_object nullobj = nullptr;
52             return nullobj;
53         }
54 
55         ani_object obj;
56         if (ANI_OK != env->Object_New(clazz, ctor, &obj, reinterpret_cast<ani_long>(nativePtr))) {
57             return nullptr;
58         }
59         return obj;
60     }
61 
Unwrap(ani_env * env,ani_object object)62     static T* Unwrap(ani_env *env, ani_object object)
63     {
64         if (env == nullptr) {
65             return nullptr;
66         }
67         ani_long nativePtr;
68         if (ANI_OK != env->Object_GetFieldByName_Long(object, "nativePtr", &nativePtr)) {
69             return nullptr;
70         }
71         return reinterpret_cast<T*>(nativePtr);
72     }
73 };
74 
75 class NativeObject {
76 public:
77     virtual ~NativeObject() = default;
78 };
79 
80 template<typename T>
81 class NativeObjectAdapter : public NativeObject {
82 public:
NativeObjectAdapter()83     explicit NativeObjectAdapter()
84     {
85         obj_ = std::make_shared<T>();
86     }
87 
Get()88     std::shared_ptr<T> Get()
89     {
90         return obj_;
91     }
92 
93 private:
94     std::shared_ptr<T> obj_;
95 };
96 
97 class NativeObjectManager {
98 public:
GetInstance()99     static NativeObjectManager& GetInstance()
100     {
101         static NativeObjectManager instance;
102         return instance;
103     }
104 
105     template<typename T>
Get(ani_object & object)106     std::shared_ptr<T> Get(ani_object &object)
107     {
108         std::lock_guard<std::mutex> lockGuard(mutex_);
109 
110         auto iter = aniToNativeObjMapper_.find(object);
111         if (iter != aniToNativeObjMapper_.end()) {
112             return std::static_pointer_cast<NativeObjectAdapter<T>>(iter->second)->Get();
113         }
114         auto nativeObj = std::make_shared<NativeObjectAdapter<T>>();
115         aniToNativeObjMapper_.emplace(object, nativeObj);
116         return nativeObj->Get();
117     }
118 
119 private:
120     std::unordered_map<ani_object, std::shared_ptr<NativeObject>> aniToNativeObjMapper_;
121     std::mutex mutex_;
122 };
123 
ANIUtils_ANIStringToStdString(ani_env * env,ani_string ani_str)124 std::string ANIUtils_ANIStringToStdString(ani_env *env, ani_string ani_str)
125 {
126     if (env == nullptr) {
127         return "";
128     }
129     ani_size strSize;
130     env->String_GetUTF8Size(ani_str, &strSize);
131 
132     std::vector<char> buffer(strSize + 1); // +1 for null terminator
133     char* utf8_buffer = buffer.data();
134 
135     ani_size bytes_written = 0;
136     env->String_GetUTF8(ani_str, utf8_buffer, strSize + 1, &bytes_written);
137 
138     utf8_buffer[bytes_written] = '\0';
139     std::string content = std::string(utf8_buffer);
140     return content;
141 }
142 
ANIUtils_UnionIsInstanceOf(ani_env * env,ani_object union_obj,std::string & cls_name)143 bool ANIUtils_UnionIsInstanceOf(ani_env *env, ani_object union_obj, std::string& cls_name)
144 {
145     if (env == nullptr) {
146         return false;
147     }
148     ani_class cls;
149     env->FindClass(cls_name.c_str(), &cls);
150 
151     ani_boolean ret;
152     env->Object_InstanceOf(union_obj, cls, &ret);
153     return ret;
154 }
155 
156 class UnionAccessor {
157 public:
UnionAccessor(ani_env * env,ani_object & obj)158     UnionAccessor(ani_env *env, ani_object &obj) : env_(env), obj_(obj)
159     {
160     }
161 
IsInstanceOf(const std::string & cls_name)162     bool IsInstanceOf(const std::string& cls_name)
163     {
164         if (env_ == nullptr) {
165             return false;
166         }
167         ani_class cls;
168         env_->FindClass(cls_name.c_str(), &cls);
169 
170         ani_boolean ret;
171         env_->Object_InstanceOf(obj_, cls, &ret);
172         return ret;
173     }
174 
175     template<typename T>
176     bool TryConvert(T &value);
177 
178 private:
179     ani_env *env_;
180     ani_object obj_;
181 };
182 
183 template<>
184 bool UnionAccessor::TryConvert<ani_boolean>(ani_boolean &value)
185 {
186     if (env_ == nullptr) {
187         return false;
188     }
189     return ANI_OK == env_->Object_CallMethodByName_Boolean(obj_, "booleanValue", nullptr, &value);
190 }
191 
192 template<>
193 bool UnionAccessor::TryConvert<ani_double>(ani_double &value)
194 {
195     if (env_ == nullptr) {
196         return false;
197     }
198     return ANI_OK == env_->Object_CallMethodByName_Double(obj_, "doubleValue", nullptr, &value);
199 }
200 
201 template<>
202 bool UnionAccessor::TryConvert<ani_string>(ani_string &value)
203 {
204     value = static_cast<ani_string>(obj_);
205     return true;
206 }
207 
208 template<>
209 bool UnionAccessor::TryConvert<std::string>(std::string &value)
210 {
211     value = ANIUtils_ANIStringToStdString(env_, static_cast<ani_string>(obj_));
212     return true;
213 }
214 
215 template<typename T>
216 class SharedPtrHolder : public NativeObject {
217 public:
SharedPtrHolder(std::shared_ptr<T> & sptr)218     SharedPtrHolder(std::shared_ptr<T> &sptr) : sptr_(sptr)
219     {
220     }
221 
Get()222     std::shared_ptr<T> Get()
223     {
224         return sptr_;
225     }
226 
GetOrDefault()227     std::shared_ptr<T> GetOrDefault()
228     {
229         if (!sptr_) {
230             sptr_ = std::make_shared<T>();
231         }
232         return sptr_;
233     }
234 
235 private:
236     std::shared_ptr<T> sptr_;
237 };
238 
239 class NativePtrCleaner {
240     public:
Clean(ani_env * env,ani_object object)241         static void Clean([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object object)
242         {
243             ani_long ptr = 0;
244             if (ANI_OK != env->Object_GetFieldByName_Long(object, "targetPtr", &ptr)) {
245                 return;
246             }
247 
248             if (ptr != 0) {
249                 delete reinterpret_cast<NativeObject *>(ptr);
250                 ptr = 0;
251             }
252         }
253 
NativePtrCleaner(ani_env * env)254         NativePtrCleaner(ani_env *env)
255             : env_(env)
256         {
257         }
258 
Bind(ani_class cls)259         ani_status Bind(ani_class cls)
260         {
261             std::array methods = {
262                 ani_native_function { "clean", nullptr, reinterpret_cast<void *>(NativePtrCleaner::Clean) },
263             };
264 
265             if (env_ == nullptr) {
266                 return (ani_status)ANI_ERROR;
267             }
268             if (ANI_OK != env_->Class_BindNativeMethods(cls, methods.data(), methods.size())) {
269                 return (ani_status)ANI_ERROR;
270             };
271 
272             return ANI_OK;
273         }
274 
275     private:
276         ani_env *env_ = nullptr;
277 };
278 #endif
279