• 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 #define LOG_TAG "AniUtils"
17 #include "ani_utils.h"
18 #include "asset_value.h"
19 #include "big_integer.h"
20 #include "values_bucket.h"
21 #include "logger.h"
22 
23 using namespace OHOS::NativeRdb;
24 using namespace OHOS::Rdb;
25 
26 
27 template<>
IsInstanceOfType()28 bool UnionAccessor::IsInstanceOfType<bool>()
29 {
30     return IsInstanceOf("Lstd/core/Boolean;");
31 }
32 
33 template<>
IsInstanceOfType()34 bool UnionAccessor::IsInstanceOfType<int>()
35 {
36     return IsInstanceOf("Lstd/core/Int;");
37 }
38 
39 template<>
IsInstanceOfType()40 bool UnionAccessor::IsInstanceOfType<double>()
41 {
42     return IsInstanceOf("Lstd/core/Double;");
43 }
44 
45 template<>
IsInstanceOfType()46 bool UnionAccessor::IsInstanceOfType<std::string>()
47 {
48     return IsInstanceOf("Lstd/core/String;");
49 }
50 
51 template<>
TryConvertArray(std::vector<ani_ref> & value)52 bool UnionAccessor::TryConvertArray<ani_ref>(std::vector<ani_ref> &value)
53 {
54     ani_double length;
55     if (ANI_OK != env_->Object_GetPropertyByName_Double(obj_, "length", &length)) {
56         LOG_ERROR("Object_GetPropertyByName_Double length failed");
57         return false;
58     }
59     for (int i = 0; i < int(length); i++) {
60         ani_ref ref;
61         if (ANI_OK != env_->Object_CallMethodByName_Ref(obj_, "$_get", "I:Lstd/core/Object;", &ref, (ani_int)i)) {
62             LOG_ERROR("Object_GetPropertyByName_Ref failed");
63             return false;
64         }
65         value.push_back(ref);
66     }
67     LOG_DEBUG("convert ref array ok.");
68     return true;
69 }
70 
71 template<>
TryConvertArray(std::vector<bool> & value)72 bool UnionAccessor::TryConvertArray<bool>(std::vector<bool> &value)
73 {
74     ani_double length;
75     if (ANI_OK != env_->Object_GetPropertyByName_Double(obj_, "length", &length)) {
76         LOG_ERROR("Object_GetPropertyByName_Double length failed");
77         return false;
78     }
79     for (int i = 0; i < int(length); i++) {
80         ani_ref ref;
81         if (ANI_OK != env_->Object_CallMethodByName_Ref(obj_, "$_get", "I:Lstd/core/Object;", &ref, (ani_int)i)) {
82             LOG_ERROR("Object_GetPropertyByName_Ref failed");
83             return false;
84         }
85         ani_boolean val;
86         if (ANI_OK != env_->Object_CallMethodByName_Boolean(static_cast<ani_object>(ref), "unboxed", nullptr, &val)) {
87             LOG_ERROR("Object_CallMethodByName_Boolean unbox failed");
88             return false;
89         }
90         value.push_back(static_cast<bool>(val));
91     }
92     LOG_DEBUG("convert bool array ok.");
93     return true;
94 }
95 
96 template<>
TryConvertArray(std::vector<int> & value)97 bool UnionAccessor::TryConvertArray<int>(std::vector<int> &value)
98 {
99     ani_double length;
100     if (ANI_OK != env_->Object_GetPropertyByName_Double(obj_, "length", &length)) {
101         LOG_ERROR("Object_GetPropertyByName_Double length failed");
102         return false;
103     }
104     for (int i = 0; i < int(length); i++) {
105         ani_ref ref;
106         if (ANI_OK != env_->Object_CallMethodByName_Ref(obj_, "$_get", "I:Lstd/core/Object;", &ref, (ani_int)i)) {
107             LOG_ERROR("Object_GetPropertyByName_Ref failed");
108             return false;
109         }
110         ani_int intValue;
111         if (ANI_OK != env_->Object_CallMethodByName_Int(static_cast<ani_object>(ref), "unboxed", nullptr, &intValue)) {
112             LOG_ERROR("Object_CallMethodByName_Int unbox failed");
113             return false;
114         }
115         value.push_back(static_cast<int>(intValue));
116     }
117     LOG_DEBUG("convert int array ok.");
118     return true;
119 }
120 
121 template<>
TryConvertArray(std::vector<double> & value)122 bool UnionAccessor::TryConvertArray<double>(std::vector<double> &value)
123 {
124     ani_double length;
125     if (ANI_OK != env_->Object_GetPropertyByName_Double(obj_, "length", &length)) {
126         LOG_ERROR("Object_GetPropertyByName_Double length failed");
127         return false;
128     }
129     for (int i = 0; i < int(length); i++) {
130         ani_ref ref;
131         if (ANI_OK != env_->Object_CallMethodByName_Ref(obj_, "$_get", "I:Lstd/core/Object;", &ref, (ani_int)i)) {
132             LOG_ERROR("Object_GetPropertyByName_Ref failed");
133             return false;
134         }
135         ani_double val;
136         if (ANI_OK != env_->Object_CallMethodByName_Double(static_cast<ani_object>(ref), "unboxed", nullptr, &val)) {
137             LOG_ERROR("Object_CallMethodByName_Double unbox failed");
138             return false;
139         }
140         value.push_back(static_cast<double>(val));
141     }
142     LOG_DEBUG("convert double array ok.");
143     return true;
144 }
145 
146 template<>
TryConvertArray(std::vector<uint8_t> & value)147 bool UnionAccessor::TryConvertArray<uint8_t>(std::vector<uint8_t> &value)
148 {
149     ani_ref buffer;
150     if (ANI_OK != env_->Object_GetFieldByName_Ref(obj_, "buffer", &buffer)) {
151         LOG_ERROR("Object_GetFieldByName_Ref failed");
152         return false;
153     }
154     void* data;
155     size_t size;
156     if (ANI_OK != env_->ArrayBuffer_GetInfo(static_cast<ani_arraybuffer>(buffer), &data, &size)) {
157         LOG_ERROR("ArrayBuffer_GetInfo failed");
158         return false;
159     }
160     for (size_t i = 0; i < size; i++) {
161         value.push_back(static_cast<uint8_t*>(data)[i]);
162     }
163     LOG_DEBUG("convert uint8 array ok.");
164     return true;
165 }
166 
167 template<>
TryConvertArray(std::vector<float> & value)168 bool UnionAccessor::TryConvertArray<float>(std::vector<float> &value)
169 {
170     ani_ref buffer;
171     if (ANI_OK != env_->Object_GetFieldByName_Ref(obj_, "buffer", &buffer)) {
172         LOG_ERROR("Object_GetFieldByName_Ref failed");
173         return false;
174     }
175     void* data;
176     size_t size;
177     if (ANI_OK != env_->ArrayBuffer_GetInfo(static_cast<ani_arraybuffer>(buffer), &data, &size)) {
178         LOG_ERROR("ArrayBuffer_GetInfo failed");
179         return false;
180     }
181     auto count = size / sizeof(float);
182     for (size_t i = 0; i < count; i++) {
183         value.push_back(static_cast<uint8_t*>(data)[i]);
184     }
185     LOG_DEBUG("convert float array ok.");
186     return true;
187 }
188 
189 template<>
TryConvertArray(std::vector<std::string> & value)190 bool UnionAccessor::TryConvertArray<std::string>(std::vector<std::string> &value)
191 {
192     ani_double length;
193     if (ANI_OK != env_->Object_GetPropertyByName_Double(obj_, "length", &length)) {
194         LOG_ERROR("Object_GetPropertyByName_Double length failed");
195         return false;
196     }
197 
198     for (int i = 0; i < int(length); i++) {
199         ani_ref ref;
200         if (ANI_OK != env_->Object_CallMethodByName_Ref(obj_, "$_get", "I:Lstd/core/Object;", &ref, (ani_int)i)) {
201             LOG_ERROR("Object_CallMethodByName_Ref failed");
202             return false;
203         }
204         value.push_back(AniStringUtils::ToStd(env_, static_cast<ani_string>(ref)));
205     }
206     LOG_DEBUG("convert string array ok.");
207     return true;
208 }
209 
210 template<>
TryConvert(int & value)211 bool UnionAccessor::TryConvert<int>(int &value)
212 {
213     if (!IsInstanceOfType<int>()) {
214         return false;
215     }
216 
217     ani_int aniValue;
218     auto ret = env_->Object_CallMethodByName_Int(obj_, "unboxed", nullptr, &aniValue);
219     if (ret != ANI_OK) {
220         return false;
221     }
222     value = static_cast<int>(aniValue);
223     LOG_DEBUG("convert int ok.");
224     return true;
225 }
226 
227 template<>
TryConvert(std::monostate & value)228 bool UnionAccessor::TryConvert<std::monostate>(std::monostate &value)
229 {
230     ani_boolean isNull = false;
231     auto status = env_->Reference_IsNull(static_cast<ani_ref>(obj_), &isNull);
232     if (ANI_OK == status) {
233         if (isNull) {
234             value = std::monostate();
235             LOG_DEBUG("convert null ok.");
236             return true;
237         }
238     }
239     return false;
240 }
241 
242 template<>
TryConvert(int64_t & value)243 bool UnionAccessor::TryConvert<int64_t>(int64_t &value)
244 {
245     return false;
246 }
247 
248 template<>
TryConvert(double & value)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     LOG_DEBUG("convert double ok.");
262     return true;
263 }
264 
265 template<>
TryConvert(std::string & value)266 bool UnionAccessor::TryConvert<std::string>(std::string &value)
267 {
268     if (!IsInstanceOfType<std::string>()) {
269         return false;
270     }
271 
272     value = AniStringUtils::ToStd(env_, static_cast<ani_string>(obj_));
273     LOG_DEBUG("convert string ok.");
274     return true;
275 }
276 
277 template<>
TryConvert(bool & value)278 bool UnionAccessor::TryConvert<bool>(bool &value)
279 {
280     if (!IsInstanceOfType<bool>()) {
281         return false;
282     }
283 
284     ani_boolean aniValue;
285     auto ret = env_->Object_CallMethodByName_Boolean(obj_, "unboxed", nullptr, &aniValue);
286     if (ret != ANI_OK) {
287         return false;
288     }
289     value = static_cast<bool>(aniValue);
290     LOG_DEBUG("convert bool ok.");
291     return true;
292 }
293 
294 template<>
TryConvert(std::vector<uint8_t> & value)295 bool UnionAccessor::TryConvert<std::vector<uint8_t>>(std::vector<uint8_t> &value)
296 {
297     if (!IsInstanceOf("Lescompat/Uint8Array;")) {
298         return false;
299     }
300     return TryConvertArray(value);
301 }
302 
GetObjectRefPropertyByName(std::string clsName,const char * name,ani_ref & val)303 bool UnionAccessor::GetObjectRefPropertyByName(std::string clsName, const char *name, ani_ref &val)
304 {
305     ani_class cls;
306     env_->FindClass(clsName.c_str(), &cls);
307     ani_method getter;
308     if (ANI_OK != env_->Class_FindGetter(cls, name,  &getter)) {
309         LOG_ERROR("GetObjectRefPropertyByName Class_FindGetter failed");
310         return false;
311     }
312     ani_ref ref;
313     if (ANI_OK != env_->Object_CallMethod_Ref(obj_, getter, &ref)) {
314         LOG_ERROR("GetObjectRefPropertyByName Object_CallMethod_Ref failed");
315         return false;
316     }
317     val = ref;
318     return true;
319 }
320 
GetObjectStringPropertyByName(std::string clsName,const char * name,std::string & val)321 bool UnionAccessor::GetObjectStringPropertyByName(std::string clsName, const char *name, std::string &val)
322 {
323     ani_ref ref;
324     auto isOk = GetObjectRefPropertyByName(clsName, name, ref);
325     if (!isOk) {
326         LOG_ERROR("GetObjectRefPropertyByName failed");
327         return false;
328     }
329     val = AniStringUtils::ToStd(env_, static_cast<ani_string>(ref));
330     return true;
331 }
332 
GetObjectEnumValuePropertyByName(std::string clsName,const char * name,ani_int & val,bool optional)333 bool UnionAccessor::GetObjectEnumValuePropertyByName(
334     std::string clsName, const char *name, ani_int &val, bool optional)
335 {
336     ani_ref ref;
337     auto isOk = GetObjectRefPropertyByName(clsName, name, ref);
338     if (!isOk) {
339         LOG_ERROR("GetObjectRefPropertyByName failed");
340         return false;
341     }
342     if (optional) {
343         ani_boolean isUndefined;
344         auto err = env_->Reference_IsUndefined(ref, &isUndefined);
345         if (err != ANI_OK) {
346             LOG_ERROR("Reference_IsUndefined fail.");
347             return false;
348         }
349         if (isUndefined) {
350             LOG_DEBUG("Optional enum item undefined.");
351             return true;
352         }
353     }
354     ani_int enumValue;
355     auto status = env_->EnumItem_GetValue_Int(static_cast<ani_enum_item>(ref), &enumValue);
356     if (status != ANI_OK) {
357         LOG_ERROR("EnumItem_GetValue_Int failed");
358         return false;
359     }
360     val = enumValue;
361     return true;
362 }
363 
364 template<>
TryConvert(AssetValue & value)365 bool UnionAccessor::TryConvert<AssetValue>(AssetValue &value)
366 {
367     std::string clsName = "L@ohos/data/relationalStore/relationalStore/Asset;";
368     if (!IsInstanceOf(clsName)) {
369         return false;
370     }
371     auto isOk = GetObjectStringPropertyByName(clsName, "name", value.name);
372     if (!isOk) {
373         return false;
374     }
375     isOk = GetObjectStringPropertyByName(clsName, "uri", value.uri);
376     if (!isOk) {
377         return false;
378     }
379     isOk = GetObjectStringPropertyByName(clsName, "path", value.path);
380     if (!isOk) {
381         return false;
382     }
383     isOk = GetObjectStringPropertyByName(clsName, "createTime", value.createTime);
384     if (!isOk) {
385         return false;
386     }
387     isOk = GetObjectStringPropertyByName(clsName, "modifyTime", value.modifyTime);
388     if (!isOk) {
389         return false;
390     }
391     isOk = GetObjectStringPropertyByName(clsName, "size", value.size);
392     if (!isOk) {
393         return false;
394     }
395     ani_int enumVal = 0;
396     isOk = GetObjectEnumValuePropertyByName(clsName, "status", enumVal, true);
397     if (!isOk) {
398         return false;
399     }
400     value.status = static_cast<AssetValue::Status>(enumVal);
401     if (value.status != AssetValue::STATUS_DELETE) {
402         value.status = AssetValue::STATUS_UNKNOWN;
403     }
404     value.hash = value.modifyTime + "_" + value.size;
405     LOG_DEBUG("convert asset ok.");
406     return true;
407 }
408 
409 template<>
TryConvert(std::vector<AssetValue> & value)410 bool UnionAccessor::TryConvert<std::vector<AssetValue>>(std::vector<AssetValue> &value)
411 {
412     std::string clsName = "[L@ohos/data/relationalStore/relationalStore/Asset;";
413     if (!IsInstanceOf(clsName)) {
414         return false;
415     }
416     ani_size arrayLength;
417     auto status = env_->Array_GetLength(static_cast<ani_array>(obj_), &arrayLength);
418     if (status != ANI_OK) {
419         LOG_ERROR("Array_GetLength failed");
420         return false;
421     }
422     for (int i = 0; i < int(arrayLength); i++) {
423         ani_ref result;
424         status = env_->Array_Get_Ref(static_cast<ani_array_ref>(obj_), i, &result);
425         if (status != ANI_OK) {
426             LOG_ERROR("Array_Get_Ref failed");
427             return false;
428         }
429         ani_object asset = static_cast<ani_object>(result);
430         UnionAccessor sub(env_, asset);
431         AssetValue val;
432         auto isOk = sub.TryConvert(val);
433         if (!isOk) {
434             return false;
435         }
436         value.push_back(val);
437     }
438     LOG_DEBUG("convert assets ok.");
439     return true;
440 }
441 
442 template<>
TryConvert(std::vector<float> & value)443 bool UnionAccessor::TryConvert<std::vector<float>>(std::vector<float> &value)
444 {
445     if (!IsInstanceOf("Lescompat/Float32Array;")) {
446         return false;
447     }
448     return TryConvertArray(value);
449 }
450 
451 template<>
TryConvert(BigInteger & value)452 bool UnionAccessor::TryConvert<BigInteger>(BigInteger &value)
453 {
454     std::string clsName = "Lescompat/BigInt;";
455     ani_class cls;
456     auto status = env_->FindClass(clsName.c_str(), &cls);
457     if (status != ANI_OK) {
458         LOG_ERROR("FindClass failed");
459         return false;
460     }
461 
462     ani_boolean ret;
463     env_->Object_InstanceOf(obj_, cls, &ret);
464     if (!ret) {
465         return false;
466     }
467 
468     ani_method getLongMethod;
469     if (ANI_OK != env_->Class_FindMethod(cls, "getLong", ":J", &getLongMethod)) {
470         LOG_ERROR("Class_FindMethod failed");
471         return false;
472     }
473 
474     ani_long longNum;
475     if (ANI_OK != env_->Object_CallMethod_Long(obj_, getLongMethod, &longNum)) {
476         LOG_ERROR("Object_CallMethod_Long failed");
477         return false;
478     }
479     value = BigInteger(longNum);
480     LOG_DEBUG("convert bigint ok.");
481     return true;
482 }
483 
484 template<>
TryConvert(std::vector<ani_ref> & value)485 bool UnionAccessor::TryConvert<std::vector<ani_ref>>(std::vector<ani_ref> &value)
486 {
487     if (!IsInstanceOf("Lescompat/Array;")) {
488         return false;
489     }
490     return TryConvertArray(value);
491 }
492 
AniIteratorNext(ani_ref interator,bool & isSuccess)493 ani_ref UnionAccessor::AniIteratorNext(ani_ref interator, bool &isSuccess)
494 {
495     ani_ref next;
496     ani_boolean done;
497     if (ANI_OK != env_->Object_CallMethodByName_Ref(static_cast<ani_object>(interator), "next", nullptr, &next)) {
498         LOG_ERROR("Failed to get next key");
499         isSuccess = false;
500         return nullptr;
501     }
502 
503     if (ANI_OK != env_->Object_GetFieldByName_Boolean(static_cast<ani_object>(next), "done", &done)) {
504         LOG_ERROR("Failed to check iterator done");
505         isSuccess = false;
506         return nullptr;
507     }
508     if (done) {
509         return nullptr;
510     }
511     return next;
512 }
513 
514 template<>
TryConvert(ValuesBucket & value)515 bool UnionAccessor::TryConvert<ValuesBucket>(ValuesBucket &value)
516 {
517     if (!IsInstanceOf("Lescompat/Record;")) {
518         return false;
519     }
520     ani_ref keys;
521     auto status = env_->Object_CallMethodByName_Ref(obj_, "keys", ":Lescompat/IterableIterator;", &keys);
522     if (status != ANI_OK) {
523         LOG_ERROR("Object_CallMethodByName_Ref failed");
524     }
525     bool success = true;
526     ani_ref next = AniIteratorNext(keys, success);
527     while (next) {
528         ani_ref key_value;
529         if (ANI_OK != env_->Object_GetFieldByName_Ref(static_cast<ani_object>(next), "value", &key_value)) {
530             LOG_ERROR("Failed to get key value");
531             success = false;
532             break;
533         }
534 
535         ani_ref valueObj;
536         if (ANI_OK != env_->Object_CallMethodByName_Ref(obj_, "$_get", nullptr, &valueObj, key_value)) {
537             LOG_ERROR("Failed to get value for key");
538             success = false;
539             break;
540         }
541         ani_object recordValue = static_cast<ani_object>(valueObj);
542         UnionAccessor sub(env_, recordValue);
543         ValueObject val;
544         success = sub.TryConvertVariant(val.value);
545         if (success) {
546             value.Put(AniStringUtils::ToStd(env_, static_cast<ani_string>(key_value)), val);
547         } else {
548             LOG_ERROR("Failed to convert AssetValue");
549             break;
550         }
551         next = AniIteratorNext(keys, success);
552     }
553     return success;
554 }
555 
556 template<>
Convert()557 std::optional<double> OptionalAccessor::Convert<double>()
558 {
559     if (IsUndefined()) {
560         return std::nullopt;
561     }
562 
563     ani_double aniValue;
564     auto ret = env_->Object_CallMethodByName_Double(obj_, "doubleValue", nullptr, &aniValue);
565     if (ret != ANI_OK) {
566         return std::nullopt;
567     }
568     auto value = static_cast<double>(aniValue);
569     return value;
570 }
571 
572 template<>
Convert()573 std::optional<std::string> OptionalAccessor::Convert<std::string>()
574 {
575     if (IsUndefined()) {
576         return std::nullopt;
577     }
578 
579     ani_size strSize;
580     env_->String_GetUTF8Size(static_cast<ani_string>(obj_), &strSize);
581 
582     std::vector<char> buffer(strSize + 1);
583     char* utf8_buffer = buffer.data();
584 
585     ani_size bytes_written = 0;
586     env_->String_GetUTF8(static_cast<ani_string>(obj_), utf8_buffer, strSize + 1, &bytes_written);
587 
588     utf8_buffer[bytes_written] = '\0';
589     std::string content = std::string(utf8_buffer);
590     return content;
591 }
592 
CleanNativePtr(ani_env * env,ani_object object)593 static void CleanNativePtr(ani_env *env, ani_object object)
594 {
595     if (env == nullptr) {
596         LOG_ERROR("env is nullptr.");
597         return;
598     }
599     ani_long ptr = 0;
600     if (ANI_OK != env->Object_GetFieldByName_Long(object, "targetPtr", &ptr)) {
601         LOG_ERROR("Can not get targetPtr.");
602         return;
603     }
604     delete reinterpret_cast<NativeObject *>(ptr);
605 }
606 
CleanerInit(ani_env * env)607 ani_status CleanerInit(ani_env *env)
608 {
609     if (env == nullptr) {
610         LOG_ERROR("env is nullptr.");
611         return ANI_ERROR;
612     }
613 
614     static const char *namespaceName = "L@ohos/data/relationalStore/relationalStore;";
615     ani_namespace ns;
616     if (ANI_OK != env->FindNamespace(namespaceName, &ns)) {
617         LOG_ERROR("Not found '%{public}s", namespaceName);
618         return ANI_ERROR;
619     }
620 
621     ani_class cls;
622     const char *className = "LCleaner;";
623     if (ANI_OK != env->Namespace_FindClass(ns, className, &cls)) {
624         LOG_ERROR("Not found '%{public}s", className);
625         return ANI_ERROR;
626     }
627 
628     std::array methods = {
629         ani_native_function {"clean", nullptr, reinterpret_cast<void *>(CleanNativePtr)},
630     };
631     if (ANI_OK != env->Class_BindNativeMethods(cls, methods.data(), methods.size())) {
632         LOG_ERROR("Cannot bind native methods to '%{public}s", className);
633         return ANI_ERROR;
634     }
635     return ANI_OK;
636 }
637