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