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 "type_converter.h"
17
18 #include <cstdint>
19 #include <cstring>
20 #include <optional>
21
22 #include "ani_signature.h"
23 #include "file_utils.h"
24 #include "filemgmt_libhilog.h"
25 #include "securec.h"
26
27 namespace OHOS::FileManagement::ModuleFileIO::ANI {
28 using namespace OHOS::FileManagement::ModuleFileIO::ANI::AniSignature;
29
ToUTF8String(ani_env * env,const ani_string & path)30 std::tuple<bool, std::string> TypeConverter::ToUTF8String(ani_env *env, const ani_string &path)
31 {
32 if (env == nullptr) {
33 return { false, EMPTY_STRING };
34 }
35 ani_size sz {};
36 std::string result;
37 auto status = env->String_GetUTF8Size(path, &sz);
38 if (status != ANI_OK) {
39 return { false, EMPTY_STRING };
40 }
41 result.resize(sz + 1);
42 status = env->String_GetUTF8SubString(path, 0, sz, result.data(), result.size(), &sz);
43 if (status != ANI_OK) {
44 return { false, EMPTY_STRING };
45 }
46 result.resize(sz);
47 return { true, std::move(result) };
48 }
49
ToOptionalInt32(ani_env * env,const ani_object & value)50 std::tuple<bool, std::optional<int32_t>> TypeConverter::ToOptionalInt32(ani_env *env, const ani_object &value)
51 {
52 if (env == nullptr) {
53 return { false, {} };
54 }
55 ani_boolean isUndefined;
56 env->Reference_IsUndefined(value, &isUndefined);
57 if (isUndefined) {
58 return { true, std::nullopt };
59 }
60
61 ani_int intValue;
62 if (ANI_OK == env->Object_CallMethodByName_Int(value, BasicTypesConverter::toInt.c_str(), nullptr, &intValue)) {
63 return { true, std::make_optional(intValue) };
64 }
65
66 return { false, {} };
67 }
68
ToOptionalInt64(ani_env * env,const ani_object & value)69 std::tuple<bool, std::optional<int64_t>> TypeConverter::ToOptionalInt64(ani_env *env, const ani_object &value)
70 {
71 if (env == nullptr) {
72 return { false, {} };
73 }
74
75 ani_boolean isUndefined;
76 env->Reference_IsUndefined(value, &isUndefined);
77 if (isUndefined) {
78 return { true, std::nullopt };
79 }
80
81 ani_long longValue;
82 if (ANI_OK == env->Object_CallMethodByName_Long(value, BasicTypesConverter::toLong.c_str(), nullptr, &longValue)) {
83 return { true, std::make_optional(longValue) };
84 }
85
86 return { false, {} };
87 }
88
ToAniString(ani_env * env,std::string str)89 std::tuple<bool, ani_string> TypeConverter::ToAniString(ani_env *env, std::string str)
90 {
91 if (env == nullptr) {
92 return { false, {} };
93 }
94
95 ani_string result;
96 if (ANI_OK != env->String_NewUTF8(str.c_str(), str.size(), &result)) {
97 return { false, {} };
98 }
99 return { true, std::move(result) };
100 }
101
ToAniString(ani_env * env,std::string str,size_t size)102 std::tuple<bool, ani_string> TypeConverter::ToAniString(ani_env *env, std::string str, size_t size)
103 {
104 if (env == nullptr) {
105 return { false, {} };
106 }
107
108 ani_string result;
109 if (ANI_OK != env->String_NewUTF8(str.c_str(), size, &result)) {
110 return { false, {} };
111 }
112 return { true, std::move(result) };
113 }
114
ToAniString(ani_env * env,const char * str)115 std::tuple<bool, ani_string> TypeConverter::ToAniString(ani_env *env, const char *str)
116 {
117 if (env == nullptr) {
118 return { false, {} };
119 }
120
121 size_t length = std::strlen(str);
122 ani_string result;
123 if (ANI_OK != env->String_NewUTF8(str, length, &result)) {
124 return { false, {} };
125 }
126 return { true, std::move(result) };
127 }
128
EnumToInt32(ani_env * env,const ani_enum_item & enumOp)129 std::tuple<bool, std::optional<int32_t>> TypeConverter::EnumToInt32(ani_env *env, const ani_enum_item &enumOp)
130 {
131 ani_boolean isUndefined;
132 env->Reference_IsUndefined(enumOp, &isUndefined);
133 if (isUndefined) {
134 return { true, std::nullopt };
135 }
136
137 ani_int result;
138 if (ANI_OK != env->EnumItem_GetValue_Int(enumOp, &result)) {
139 return { false, {} };
140 }
141
142 return { true, std::make_optional(result) };
143 }
144
ParseFd(ani_env * env,const ani_object & pathOrFd)145 static std::tuple<bool, int32_t> ParseFd(ani_env *env, const ani_object &pathOrFd)
146 {
147 ani_boolean isFd = false;
148
149 auto classDesc = BoxedTypes::Double::classDesc.c_str();
150 ani_class cls;
151 env->FindClass(classDesc, &cls);
152 env->Object_InstanceOf(pathOrFd, cls, &isFd);
153 if (isFd) {
154 ani_int fd;
155 if (ANI_OK != env->Object_CallMethodByName_Int(pathOrFd, BasicTypesConverter::toInt.c_str(), nullptr, &fd)) {
156 HILOGE("Parse file path failed");
157 return { false, 0 };
158 }
159 return { true, fd };
160 }
161
162 return { false, 0 };
163 }
164
ToFileInfo(ani_env * env,const ani_object & pathOrFd)165 std::tuple<bool, FileInfo> TypeConverter::ToFileInfo(ani_env *env, const ani_object &pathOrFd)
166 {
167 if (env == nullptr) {
168 HILOGE("Invalid parameter env");
169 return { false, FileInfo { false, {}, {} } };
170 }
171
172 auto stringClassDesc = BuiltInTypes::String::classDesc.c_str();
173 ani_class stringClass;
174 env->FindClass(stringClassDesc, &stringClass);
175
176 ani_boolean isPath = false;
177 env->Object_InstanceOf(pathOrFd, stringClass, &isPath);
178 if (isPath) {
179 auto [succ, path] = TypeConverter::ToUTF8String(env, static_cast<ani_string>(pathOrFd));
180 if (!succ) {
181 HILOGE("Parse file path failed");
182 return { false, FileInfo { false, {}, {} } };
183 }
184 size_t length = path.length() + 1;
185 auto chars = std::make_unique<char[]>(length);
186 auto ret = strncpy_s(chars.get(), length, path.c_str(), length - 1);
187 if (ret != EOK) {
188 HILOGE("Copy file path failed!");
189 return { false, FileInfo { false, {}, {} } };
190 }
191 return { true, FileInfo { true, move(chars), {} } };
192 }
193
194 auto [isFd, fd] = ParseFd(env, pathOrFd);
195 if (isFd) {
196 auto fdg = CreateUniquePtr<DistributedFS::FDGuard>(fd, false);
197 if (fdg == nullptr) {
198 HILOGE("Failed to request heap memory.");
199 return { false, FileInfo { false, {}, {} } };
200 }
201 return { true, FileInfo { false, {}, move(fdg) } };
202 }
203
204 return { false, FileInfo { false, {}, {} } };
205 }
206
ToArrayBuffer(ani_env * env,ani_arraybuffer & buffer)207 std::tuple<bool, ArrayBuffer> TypeConverter::ToArrayBuffer(ani_env *env, ani_arraybuffer &buffer)
208 {
209 if (env == nullptr) {
210 return { false, ArrayBuffer { nullptr, 0 } };
211 }
212
213 void *buf = nullptr;
214 ani_size length = 0;
215
216 if (ANI_OK != env->ArrayBuffer_GetInfo(buffer, &buf, &length)) {
217 return { false, ArrayBuffer { nullptr, 0 } };
218 }
219 return { true, ArrayBuffer { std::move(buf), length } };
220 }
221
ToAniArrayBuffer(ani_env * env,void * buffer,size_t length)222 std::tuple<bool, ani_arraybuffer> TypeConverter::ToAniArrayBuffer(ani_env *env, void *buffer, size_t length)
223 {
224 if (env == nullptr) {
225 return { false, nullptr };
226 }
227
228 auto classDesc = BuiltInTypes::ArrayBuffer::classDesc.c_str();
229 ani_status ret;
230 ani_class cls;
231 if ((ret = env->FindClass(classDesc, &cls)) != ANI_OK) {
232 HILOGE("Not found %{private}s, err: %{private}d", classDesc, ret);
233 return { false, nullptr };
234 }
235
236 auto ctorDesc = BuiltInTypes::ArrayBuffer::ctorDesc.c_str();
237 auto ctorSig = BuiltInTypes::ArrayBuffer::ctorSig.c_str();
238 ani_method ctor;
239 if ((ret = env->Class_FindMethod(cls, ctorDesc, ctorSig, &ctor)) != ANI_OK) {
240 HILOGE("Not found ctor, err: %{private}d", ret);
241 return { false, nullptr };
242 }
243
244 ani_object obj;
245 if ((ret = env->Object_New(cls, ctor, &obj, length)) != ANI_OK) {
246 HILOGE("New Uint8Array err: %{private}d", ret);
247 return { false, nullptr };
248 }
249
250 if (!buffer || !length) {
251 return { true, static_cast<ani_arraybuffer>(obj) };
252 }
253
254 void *buf = nullptr;
255 ani_size len = 0;
256
257 if ((ANI_OK != env->ArrayBuffer_GetInfo(static_cast<ani_arraybuffer>(obj), &buf, &len)) && (!buf)) {
258 return { false, nullptr };
259 }
260
261 int res = memcpy_s(buf, length, buffer, length);
262 if (res != 0) {
263 return { false, nullptr };
264 }
265 len = length;
266
267 return { true, static_cast<ani_arraybuffer>(obj) };
268 }
269
ToAniStringList(ani_env * env,const std::string strList[],const uint32_t length)270 std::tuple<bool, ani_array_ref> TypeConverter::ToAniStringList(
271 ani_env *env, const std::string strList[], const uint32_t length)
272 {
273 if (env == nullptr) {
274 return { false, nullptr };
275 }
276
277 auto classDesc = BuiltInTypes::String::classDesc.c_str();
278 ani_array_ref result = nullptr;
279 ani_class cls = nullptr;
280 if (env->FindClass(classDesc, &cls) != ANI_OK) {
281 return { false, result };
282 }
283 if (env->Array_New_Ref(cls, length, nullptr, &result) != ANI_OK) {
284 return { false, result };
285 }
286 for (uint32_t i = 0; i < length; i++) {
287 auto [ret, item] = TypeConverter::ToAniString(env, strList[i]);
288 if (!ret) {
289 return { false, nullptr };
290 }
291
292 if (env->Array_Set_Ref(result, i, item) != ANI_OK) {
293 return { false, nullptr };
294 }
295 }
296 return { true, result };
297 }
298
299 } // namespace OHOS::FileManagement::ModuleFileIO::ANI