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 <iostream> 23 #include <memory> 24 #include <optional> 25 #include <string> 26 #include <vector> 27 #include "log.h" 28 #include "base.h" 29 30 namespace OHOS { 31 namespace AniUtil { 32 33 class AniObjectUtils { 34 public: Create(ani_env * env,const char * nsName,const char * clsName,...)35 static ani_object Create(ani_env *env, const char* nsName, const char* clsName, ...) 36 { 37 ani_namespace ns; 38 if (ANI_OK != env->FindNamespace(nsName, &ns)) { 39 REQUEST_HILOGE("[ANI] Not found namespace %{public}s", nsName); 40 return nullptr; 41 } 42 43 ani_class cls; 44 if (ANI_OK != env->Namespace_FindClass(ns, clsName, &cls)) { 45 REQUEST_HILOGE("[ANI] Not found namespace %{public}s", clsName); 46 return nullptr; 47 } 48 49 ani_object obj; 50 va_list args; 51 va_start(args, clsName); 52 obj = CreateV(env, cls, args); 53 va_end(args); 54 return obj; 55 } 56 Create(ani_env * env,const char * nsName,const char * subNsName,const char * clsName,...)57 static ani_object Create(ani_env *env, const char* nsName, const char* subNsName, const char* clsName, ...) 58 { 59 ani_namespace ns; 60 if (ANI_OK != env->FindNamespace(nsName, &ns)) { 61 REQUEST_HILOGE("[ANI] Not found namespace %{public}s", nsName); 62 return nullptr; 63 } 64 65 ani_namespace subNs; 66 if (ANI_OK != env->Namespace_FindNamespace(ns, subNsName, &subNs)) { 67 REQUEST_HILOGE("[ANI] Not found namespace %{public}s", subNsName); 68 return nullptr; 69 } 70 71 ani_class cls; 72 if (ANI_OK != env->Namespace_FindClass(subNs, clsName, &cls)) { 73 REQUEST_HILOGE("[ANI] Not found class %{public}s", clsName); 74 return nullptr; 75 } 76 77 ani_object obj; 78 va_list args; 79 va_start(args, clsName); 80 obj = CreateV(env, cls, args); 81 va_end(args); 82 return obj; 83 } 84 Create(ani_env * env,const char * clsName,...)85 static ani_object Create(ani_env *env, const char* clsName, ...) 86 { 87 ani_class cls; 88 if (ANI_OK != env->FindClass(clsName, &cls)) { 89 REQUEST_HILOGE("[ANI] Not found class %{public}s", clsName); 90 return nullptr; 91 } 92 93 ani_object obj; 94 va_list args; 95 va_start(args, clsName); 96 obj = CreateV(env, cls, args); 97 va_end(args); 98 return obj; 99 } 100 Create(ani_env * env,ani_class cls,...)101 static ani_object Create(ani_env *env, ani_class cls, ...) 102 { 103 ani_method ctor; 104 if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", nullptr, &ctor)) { 105 REQUEST_HILOGE("[ANI] Not found <ctor> for class"); 106 return nullptr; 107 } 108 109 ani_object obj; 110 va_list args; 111 va_start(args, cls); 112 obj = CreateV(env, cls, args); 113 va_end(args); 114 return obj; 115 } 116 From(ani_env * env,bool value)117 static ani_object From(ani_env *env, bool value) 118 { 119 return Create(env, "Lstd/core/Boolean;", static_cast<ani_boolean>(value)); 120 } 121 122 template<typename T> 123 static ani_status Wrap(ani_env *env, ani_object object, T* nativePtr, const char* propName = "nativePtr") 124 { 125 return env->Object_SetFieldByName_Long(object, propName, reinterpret_cast<ani_long>(nativePtr)); 126 } 127 128 template<typename T> 129 static T* Unwrap(ani_env *env, ani_object object, const char* propName = "nativePtr") 130 { 131 ani_long nativePtr; 132 if (ANI_OK != env->Object_GetFieldByName_Long(object, propName, &nativePtr)) { 133 return nullptr; 134 } 135 return reinterpret_cast<T*>(nativePtr); 136 } 137 138 private: CreateV(ani_env * env,ani_class cls,va_list args)139 static ani_object CreateV(ani_env *env, ani_class cls, va_list args) 140 { 141 ani_method ctor; 142 if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", nullptr, &ctor)) { 143 REQUEST_HILOGE("[ANI] Not found <ctor> for class"); 144 return nullptr; 145 } 146 147 ani_object obj; 148 ani_status status = env->Object_New_V(cls, ctor, &obj, args); 149 if (ANI_OK != status) { 150 REQUEST_HILOGE("[ANI] Failed to Object_New for class."); 151 return nullptr; 152 } 153 return obj; 154 } 155 }; 156 157 158 class AniStringUtils { 159 public: ToStd(ani_env * env,ani_string ani_str)160 static std::string ToStd(ani_env *env, ani_string ani_str) 161 { 162 ani_size strSize; 163 env->String_GetUTF8Size(ani_str, &strSize); 164 165 std::vector<char> buffer(strSize + 1); // +1 for null terminator 166 char* utf8_buffer = buffer.data(); 167 168 //String_GetUTF8 Supportted by https://gitee.com/openharmony/arkcompiler_runtime_core/pulls/3416 169 ani_size bytes_written = 0; 170 env->String_GetUTF8(ani_str, utf8_buffer, strSize + 1, &bytes_written); 171 172 utf8_buffer[bytes_written] = '\0'; 173 std::string content = std::string(utf8_buffer); 174 return content; 175 } 176 ToAni(ani_env * env,const std::string & str)177 static ani_string ToAni(ani_env* env, const std::string& str) 178 { 179 ani_string aniStr = nullptr; 180 if (ANI_OK != env->String_NewUTF8(str.data(), str.size(), &aniStr)) { 181 REQUEST_HILOGE("[ANI] Unsupported ANI_VERSION_1"); 182 return nullptr; 183 } 184 return aniStr; 185 } 186 }; 187 188 189 class UnionAccessor { 190 public: UnionAccessor(ani_env * env,ani_object obj)191 UnionAccessor(ani_env *env, ani_object obj) : env_(env), obj_(obj) 192 { 193 } 194 IsInstanceOf(const std::string & cls_name)195 bool IsInstanceOf(const std::string& cls_name) 196 { 197 ani_class cls; 198 env_->FindClass(cls_name.c_str(), &cls); 199 200 ani_boolean ret; 201 env_->Object_InstanceOf(obj_, cls, &ret); 202 return ret; 203 } 204 205 template<typename T> 206 bool IsInstanceOfType(); 207 208 template<typename T> Convert()209 expected<T, ani_status> Convert() 210 { 211 T value{}; 212 bool status = TryConvert<T>(value); 213 if (ANI_OK != status) { 214 return ANI_ERROR; 215 } 216 return value; 217 } 218 219 template<typename T> 220 bool TryConvert(T &value); 221 222 template<typename T> 223 bool TryConvertArray(std::vector<T> &value); 224 225 private: 226 ani_env *env_; 227 ani_object obj_; 228 }; 229 230 template<> 231 inline bool UnionAccessor::IsInstanceOfType<bool>() 232 { 233 return IsInstanceOf("Lstd/core/Boolean;"); 234 } 235 236 template<> 237 inline bool UnionAccessor::IsInstanceOfType<int>() 238 { 239 return IsInstanceOf("Lstd/core/Int;"); 240 } 241 242 template<> 243 inline bool UnionAccessor::IsInstanceOfType<double>() 244 { 245 return IsInstanceOf("Lstd/core/Double;"); 246 } 247 248 template<> 249 inline bool UnionAccessor::IsInstanceOfType<std::string>() 250 { 251 return IsInstanceOf("Lstd/core/String;"); 252 } 253 254 template<> 255 inline bool UnionAccessor::TryConvert<bool>(bool &value) 256 { 257 if (!IsInstanceOfType<bool>()) { 258 return false; 259 } 260 261 ani_boolean aniValue; 262 auto ret = env_->Object_CallMethodByName_Boolean(obj_, "unboxed", nullptr, &aniValue); 263 if (ret != ANI_OK) { 264 return false; 265 } 266 value = static_cast<bool>(aniValue); 267 return true; 268 } 269 270 template<> 271 inline bool UnionAccessor::TryConvert<int>(int &value) 272 { 273 if (!IsInstanceOfType<int>()) { 274 return false; 275 } 276 277 ani_int aniValue; 278 auto ret = env_->Object_CallMethodByName_Int(obj_, "unboxed", nullptr, &aniValue); 279 if (ret != ANI_OK) { 280 return false; 281 } 282 value = static_cast<int>(aniValue); 283 return true; 284 } 285 286 template<> 287 inline bool UnionAccessor::TryConvert<double>(double &value) 288 { 289 if (!IsInstanceOfType<double>()) { 290 return false; 291 } 292 293 ani_double aniValue; 294 auto ret = env_->Object_CallMethodByName_Double(obj_, "unboxed", nullptr, &aniValue); 295 if (ret != ANI_OK) { 296 return false; 297 } 298 value = static_cast<double>(aniValue); 299 return true; 300 } 301 302 template<> 303 inline bool UnionAccessor::TryConvert<std::string>(std::string &value) 304 { 305 if (!IsInstanceOfType<std::string>()) { 306 return false; 307 } 308 309 value = AniStringUtils::ToStd(env_, static_cast<ani_string>(obj_)); 310 return true; 311 } 312 313 ani_boolean IsInstanceOf(ani_env *env, const std::string &cls_name, ani_object obj); 314 315 class OptionalAccessor { 316 public: OptionalAccessor(ani_env * env,ani_object obj)317 OptionalAccessor(ani_env *env, ani_object obj) : env_(env), obj_(obj) 318 { 319 } 320 IsUndefined()321 bool IsUndefined() 322 { 323 ani_boolean isUndefined; 324 env_->Reference_IsUndefined(obj_, &isUndefined); 325 return isUndefined; 326 } 327 328 template<typename T> 329 expected<T, ani_status> Convert(); 330 331 private: ConvertToString()332 expected<std::string, ani_status> ConvertToString() 333 { 334 if (IsUndefined()) { 335 return ANI_ERROR; 336 } 337 338 ani_size strSize; 339 env_->String_GetUTF8Size(static_cast<ani_string>(obj_), &strSize); 340 341 std::vector<char> buffer(strSize + 1); 342 char* utf8_buffer = buffer.data(); 343 344 ani_size bytes_written = 0; 345 env_->String_GetUTF8(static_cast<ani_string>(obj_), utf8_buffer, strSize + 1, &bytes_written); 346 347 utf8_buffer[bytes_written] = '\0'; 348 std::string content = std::string(utf8_buffer); 349 return content; 350 } 351 352 private: 353 ani_env *env_; 354 ani_object obj_; 355 }; 356 357 template<> 358 inline expected<bool, ani_status> OptionalAccessor::Convert<bool>() 359 { 360 if (IsUndefined()) { 361 return ANI_ERROR; 362 } 363 364 ani_boolean aniValue; 365 auto ret = env_->Object_CallMethodByName_Boolean(obj_, "unboxed", nullptr, &aniValue); 366 if (ret != ANI_OK) { 367 return ret; 368 } 369 auto value = static_cast<bool>(aniValue); 370 return value; 371 } 372 373 template<> 374 inline expected<double, ani_status> OptionalAccessor::Convert<double>() 375 { 376 if (IsUndefined()) { 377 return ANI_ERROR; 378 } 379 380 ani_double aniValue; 381 auto ret = env_->Object_CallMethodByName_Double(obj_, "doubleValue", nullptr, &aniValue); 382 if (ret != ANI_OK) { 383 return ret; 384 } 385 auto value = static_cast<double>(aniValue); 386 return value; 387 } 388 389 template<> 390 inline expected<std::string, ani_status> OptionalAccessor::Convert<std::string>() 391 { 392 return ConvertToString(); 393 } 394 395 396 class EnumAccessor { 397 public: EnumAccessor(ani_env * env,const char * className,ani_int index)398 EnumAccessor(ani_env *env, const char* className, ani_int index) : env_(env) 399 { 400 initStatus_ = ANI_ERROR; 401 ani_enum_item item; 402 initStatus_ = GetItem(className, index, item); 403 if (ANI_OK == initStatus_) { 404 item_ = item; 405 } 406 } 407 EnumAccessor(ani_env * env,ani_enum_item item)408 EnumAccessor(ani_env *env, ani_enum_item item) : env_(env), item_(item) 409 { 410 initStatus_ = ANI_ERROR; 411 } 412 413 template<typename T> To()414 expected<T, ani_status> To() 415 { 416 int32_t value{}; 417 ani_status status = ToInt(value); 418 if (ANI_OK != status) { 419 return status; 420 } 421 return static_cast<T>(value); 422 } 423 ToInt(int32_t & value)424 ani_status ToInt(int32_t &value) 425 { 426 if (!item_) { 427 return initStatus_; 428 } 429 430 ani_status status = env_->EnumItem_GetValue_Int(item_.value(), &value); 431 if (ANI_OK != status) { 432 REQUEST_HILOGE("Failed to call EnumItem_GetValue_Int"); 433 return status; 434 } 435 return ANI_OK; 436 } 437 ToInt()438 expected<int32_t, ani_status> ToInt() 439 { 440 int32_t value; 441 ani_status status = ToInt(value); 442 if (ANI_OK != status) { 443 return status; 444 } 445 return value; 446 } 447 ToString(std::string & value)448 ani_status ToString(std::string &value) 449 { 450 if (!item_) { 451 return initStatus_; 452 } 453 454 ani_string strValue; 455 ani_status status = env_->EnumItem_GetValue_String(item_.value(), &strValue); 456 if (ANI_OK != status) { 457 REQUEST_HILOGE("Failed to call EnumItem_GetValue_String"); 458 return status; 459 } 460 value = AniStringUtils::ToStd(env_, strValue); 461 return ANI_OK; 462 } 463 ToString()464 expected<std::string, ani_status> ToString() 465 { 466 std::string value; 467 ani_status status = ToString(value); 468 if (ANI_OK != status) { 469 return status; 470 } 471 return value; 472 } 473 474 private: GetItem(const char * className,ani_int index,ani_enum_item & item)475 ani_status GetItem(const char* className, ani_int index, ani_enum_item &item) 476 { 477 ani_status status = ANI_ERROR; 478 ani_enum enumType; 479 status = env_->FindEnum(className, &enumType); 480 if (ANI_OK != status) { 481 REQUEST_HILOGE("Failed to call FindEnum for %{public}s", className); 482 return status; 483 } 484 485 status = env_->Enum_GetEnumItemByIndex(enumType, index, &item); 486 if (ANI_OK != status) { 487 REQUEST_HILOGE("Failed to call Enum_GetEnumItemByIndex for %{public}s, [%{public}d]", className, index); 488 return status; 489 } 490 return ANI_OK; 491 } 492 493 private: 494 ani_env *env_; 495 std::optional<ani_enum_item> item_; 496 ani_status initStatus_; 497 }; 498 499 500 class ArrayAccessor { 501 public: ArrayAccessor(ani_env * env,ani_object obj)502 ArrayAccessor(ani_env *env, ani_object obj) : env_(env), obj_(obj) 503 { 504 } 505 Length(std::size_t & length)506 ani_status Length(std::size_t &length) 507 { 508 ani_double value; 509 if (ANI_OK != env_->Object_GetPropertyByName_Double(obj_, "length", &value)) { 510 return ANI_ERROR; 511 } 512 length = static_cast<std::size_t>(value); 513 return ANI_OK; 514 } 515 516 template <typename OutputIterator, typename TransformFunc> Transform(OutputIterator out,TransformFunc && transform)517 ani_status Transform(OutputIterator out, TransformFunc&& transform) 518 { 519 ani_status status = ANI_ERROR; 520 std::size_t length = 0; 521 status = Length(length); 522 if (ANI_OK != status) { 523 return status; 524 } 525 for (std::size_t i = 0; i < length; i++) { 526 ani_ref itemRef; 527 status = env_->Object_CallMethodByName_Ref(obj_, "$_get", "I:Lstd/core/Object;", &itemRef, (ani_int)i); 528 if (ANI_OK != status) { 529 return status; 530 } 531 typename OutputIterator::container_type::value_type value; 532 status = transform(env_, itemRef, value); 533 if (ANI_OK != status) { 534 return status; 535 } 536 *out++ = value; 537 } 538 return ANI_OK; 539 } 540 541 private: 542 ani_env *env_ = nullptr; 543 ani_object obj_ = nullptr; 544 }; 545 546 struct ToDouble { operatorToDouble547 ani_status operator()(ani_env *env, ani_ref &itemRef, double &value) const 548 { 549 ani_double aniValue; 550 ani_object itemObj = static_cast<ani_object>(itemRef); 551 ani_status status = env->Object_CallMethodByName_Double(itemObj, "unboxed", nullptr, &aniValue); 552 if (ANI_OK != status) { 553 value = static_cast<double>(aniValue); 554 } 555 return status; 556 } 557 }; 558 559 560 class AniLocalScopeGuard { 561 public: AniLocalScopeGuard(ani_env * env,size_t nrRefs)562 AniLocalScopeGuard(ani_env *env, size_t nrRefs) : env_(env) 563 { 564 status_ = env_->CreateLocalScope(nrRefs); 565 } 566 ~AniLocalScopeGuard()567 ~AniLocalScopeGuard() 568 { 569 if (ANI_OK != status_) { 570 return; 571 } 572 env_->DestroyLocalScope(); 573 } 574 IsStatusOK()575 bool IsStatusOK() 576 { 577 return ANI_OK == status_; 578 } 579 GetStatus()580 ani_status GetStatus() 581 { 582 return status_; 583 } 584 585 private: 586 ani_env *env_ = nullptr; 587 ani_status status_ = ANI_ERROR; 588 }; 589 590 } // namespace AniUtil 591 } // namespace OHOS 592 593 #endif 594