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