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 "listfile_ani.h"
17
18 #include "ani_signature.h"
19 #include "error_handler.h"
20 #include "filemgmt_libhilog.h"
21 #include "listfile_core.h"
22 #include "type_converter.h"
23
24 namespace OHOS {
25 namespace FileManagement {
26 namespace ModuleFileIO {
27 namespace ANI {
28
29 using namespace std;
30 using namespace OHOS::FileManagement::ModuleFileIO;
31 using namespace OHOS::FileManagement::ModuleFileIO::ANI::AniSignature;
32
ParseBooleanParam(ani_env * env,ani_object obj,string tag)33 tuple<bool, bool> ParseBooleanParam(ani_env *env, ani_object obj, string tag)
34 {
35 ani_ref boolRef;
36 ani_boolean isUndefined;
37 if (ANI_OK != env->Object_GetPropertyByName_Ref(obj, tag.c_str(), &boolRef)) {
38 return { false, false };
39 }
40 env->Reference_IsUndefined(boolRef, &isUndefined);
41 if (isUndefined) {
42 return { true, false };
43 }
44 auto unboxedDesc = BoxedTypes::Boolean::unboxedDesc.c_str();
45 auto unboxedSig = BoxedTypes::Boolean::unboxedSig.c_str();
46 ani_boolean boolRef_res;
47 if (ANI_OK != env->Object_CallMethodByName_Boolean(
48 static_cast<ani_object>(boolRef), unboxedDesc, unboxedSig, &boolRef_res)) {
49 return { false, false };
50 }
51 return { true, static_cast<bool>(boolRef_res) };
52 }
53
ParseIntParam(ani_env * env,ani_object obj,string tag)54 tuple<bool, int> ParseIntParam(ani_env *env, ani_object obj, string tag)
55 {
56 int result = 0;
57 ani_boolean isUndefined;
58 ani_ref resultRef;
59 if (ANI_OK != env->Object_GetPropertyByName_Ref(obj, tag.c_str(), &resultRef)) {
60 return { false, result };
61 }
62 env->Reference_IsUndefined(resultRef, &isUndefined);
63 if (isUndefined) {
64 return { true, result };
65 }
66 ani_int resultRefRes;
67 if (ANI_OK != env->Object_CallMethodByName_Int(
68 static_cast<ani_object>(resultRef), BasicTypesConverter::toInt.c_str(), nullptr, &resultRefRes)) {
69 result = -1;
70 return { false, result };
71 }
72 result = static_cast<int>(resultRefRes);
73 return { true, result };
74 }
75
ParseDoubleParam(ani_env * env,ani_object obj,string tag)76 tuple<bool, optional<double>> ParseDoubleParam(ani_env *env, ani_object obj, string tag)
77 {
78 ani_boolean isUndefined;
79 ani_ref resultRef;
80 if (ANI_OK != env->Object_GetPropertyByName_Ref(obj, tag.c_str(), &resultRef)) {
81 return { false, nullopt };
82 }
83 env->Reference_IsUndefined(resultRef, &isUndefined);
84 if (isUndefined) {
85 return { true, nullopt };
86 }
87
88 ani_double resultRefRes;
89 if (ANI_OK != env->Object_CallMethodByName_Double(
90 static_cast<ani_object>(resultRef), BasicTypesConverter::toDouble.c_str(), nullptr, &resultRefRes)) {
91 return { false, nullopt };
92 }
93 double result = static_cast<double>(resultRefRes);
94 return { true, make_optional<double>(result) };
95 }
96
ParseArrayString(ani_env * env,ani_object obj,string tag)97 tuple<bool, optional<vector<string>>> ParseArrayString(ani_env *env, ani_object obj, string tag)
98 {
99 ani_boolean isUndefined;
100 ani_ref resultRef;
101 vector<string> strings;
102 if (ANI_OK != env->Object_GetPropertyByName_Ref(obj, tag.c_str(), &resultRef)) {
103 return { false, nullopt };
104 }
105 env->Reference_IsUndefined(resultRef, &isUndefined);
106 if (isUndefined) {
107 return { true, nullopt };
108 }
109
110 ani_double length;
111 if (ANI_OK != env->Object_GetPropertyByName_Double(
112 static_cast<ani_object>(resultRef), "length", &length) || length == 0) {
113 return { false, nullopt };
114 }
115 auto getterDesc = BuiltInTypes::Array::getterDesc.c_str();
116 auto getterSig = BuiltInTypes::Array::objectGetterSig.c_str();
117 for (int idx = 0; idx < int(length); idx++) {
118 ani_ref stringEntryRef;
119 if (ANI_OK != env->Object_CallMethodByName_Ref(
120 static_cast<ani_object>(resultRef), getterDesc, getterSig, &stringEntryRef, (ani_int)idx)) {
121 return { false, nullopt };
122 }
123 auto [succ, tmp] = TypeConverter::ToUTF8String(env, static_cast<ani_string>(stringEntryRef));
124 if (!succ) {
125 return { false, nullopt };
126 }
127 strings.emplace_back(tmp);
128 }
129 return { true, make_optional<vector<string>>(move(strings)) };
130 }
131
ParseFilter(ani_env * env,ani_object obj)132 tuple<bool, optional<FsFileFilter>> ParseFilter(ani_env *env, ani_object obj)
133 {
134 FsFileFilter filter;
135
136 auto [succfileSizeOver, fileSizeOver] = ParseIntParam(env, obj, "fileSizeOver");
137 if (!succfileSizeOver) {
138 HILOGE("Illegal option.fileSizeOver parameter");
139 return { false, move(filter) };
140 }
141 filter.SetFileSizeOver(fileSizeOver);
142
143 auto [succlastModifiedAfter, lastModifiedAfter] = ParseDoubleParam(env, obj, "lastModifiedAfter");
144 if (!succlastModifiedAfter) {
145 HILOGE("Illegal option.lastModifiedAfter parameter");
146 return { false, move(filter) };
147 }
148 filter.SetLastModifiedAfter(lastModifiedAfter);
149
150 auto [succSuffix, suffix] = ParseArrayString(env, obj, "suffix");
151 if (!succSuffix) {
152 HILOGE("Illegal option.suffix parameter");
153 return { false, move(filter) };
154 }
155 filter.SetSuffix(move(suffix));
156
157 auto [succDisplayName, displayName] = ParseArrayString(env, obj, "displayName");
158 if (!succDisplayName) {
159 HILOGE("Illegal option.displayName parameter");
160 return { false, move(filter) };
161 }
162 filter.SetDisplayName(move(displayName));
163
164 return { true, move(filter) };
165 }
166
ParseArgs(ani_env * env,ani_object obj)167 tuple<bool, optional<FsListFileOptions>> ParseArgs(ani_env *env, ani_object obj)
168 {
169 FsListFileOptions result;
170 ani_boolean isUndefined;
171 env->Reference_IsUndefined(obj, &isUndefined);
172 if (isUndefined) {
173 return { true, nullopt };
174 }
175
176 auto [succRecursion, recursion] = ParseBooleanParam(env, obj, "recursion");
177 if (!succRecursion) {
178 HILOGE("Invalid recursion");
179 return { false, nullopt };
180 }
181 result.recursion = recursion;
182
183 auto [succlistNum, listNumRes] = ParseIntParam(env, obj, "listNum");
184 if (!succlistNum) {
185 HILOGE("Invalid listNum");
186 return { false, nullopt };
187 }
188 result.listNum = (int)listNumRes;
189
190 ani_ref filterRef;
191 if (ANI_OK != env->Object_GetPropertyByName_Ref(obj, "filter", &filterRef)) {
192 HILOGE("Invalid filter");
193 return { false, nullopt };
194 }
195 env->Reference_IsUndefined(filterRef, &isUndefined);
196 if (isUndefined) {
197 return { true, make_optional<FsListFileOptions>(result) };
198 }
199 auto [succFilter, filterFilterClass] = ParseFilter(env, static_cast<ani_object>(filterRef));
200 if (!succFilter) {
201 HILOGE("Invalid filter");
202 return { false, nullopt };
203 }
204 result.filter = move(filterFilterClass);
205
206 return { true, make_optional<FsListFileOptions>(result) };
207 }
208
ListFileSync(ani_env * env,ani_class clazz,ani_string path,ani_object obj)209 ani_array_ref ListFileAni::ListFileSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, ani_object obj)
210 {
211 auto [succPath, srcPath] = TypeConverter::ToUTF8String(env, path);
212 if (!succPath) {
213 HILOGE("Invalid path");
214 ErrorHandler::Throw(env, EINVAL);
215 return nullptr;
216 }
217
218 auto [succOpt, opt] = ParseArgs(env, obj);
219 if (!succOpt) {
220 HILOGE("Invalid options Arguments");
221 ErrorHandler::Throw(env, EINVAL);
222 return nullptr;
223 }
224
225 auto ret = ListFileCore::DoListFile(srcPath, opt);
226 if (!ret.IsSuccess()) {
227 HILOGE("DoListFile failed");
228 const auto &err = ret.GetError();
229 ErrorHandler::Throw(env, err);
230 return nullptr;
231 }
232
233 auto fileList = ret.GetData().value();
234 const std::string *strArray = fileList.data();
235 auto [succ, result] = TypeConverter::ToAniStringList(env, strArray, fileList.size());
236 if (!succ) {
237 HILOGE("Convert list file result to ani string array failed");
238 ErrorHandler::Throw(env, UNKNOWN_ERR);
239 return nullptr;
240 }
241 return result;
242 }
243
244 } // namespace ANI
245 } // namespace ModuleFileIO
246 } // namespace FileManagement
247 } // namespace OHOS