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