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