• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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