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 "ani_util_native_ptr.h"
17 #include "common_func.h"
18 #include "file_uri_entity.h"
19 #include "file_utils.h"
20 #include "log.h"
21 #include "n_error.h"
22 #include <ani.h>
23 #include <iostream>
24 #include <vector>
25
26 using namespace OHOS::AppFileService;
27
ParseObjToStr(ani_env * env,ani_string stringObj)28 static std::string ParseObjToStr(ani_env *env, ani_string stringObj)
29 {
30 ani_size strSize;
31 env->String_GetUTF8Size(stringObj, &strSize);
32 std::vector<char> buffer(strSize + 1);
33 char *utf8Buffer = buffer.data();
34
35 ani_size byteswritten = 0;
36 env->String_GetUTF8(stringObj, utf8Buffer, strSize + 1, &byteswritten);
37
38 utf8Buffer[byteswritten] = '\0';
39 std::string path = std::string(utf8Buffer);
40 return path;
41 }
42
unwrapp(ani_env * env,ani_object object)43 static ModuleFileUri::FileUriEntity *unwrapp(ani_env *env, ani_object object)
44 {
45 ani_long fileUriEntityHolder_;
46 if (ANI_OK != env->Object_GetFieldByName_Long(object, "fileUriEntity_", &fileUriEntityHolder_)) {
47 LOGE("Get fileuriEntityHolder_ failed");
48 return nullptr;
49 }
50 auto fileUriHolder = reinterpret_cast<StdSharedPtrHolder<ModuleFileUri::FileUriEntity> *>(fileUriEntityHolder_);
51 if (!fileUriHolder) {
52 LOGE("Get fileuriEntityHolder by long ptr failed");
53 return nullptr;
54 }
55 return reinterpret_cast<ModuleFileUri::FileUriEntity *>(fileUriHolder->Get().get());
56 }
57
ThrowBusinessError(ani_env * env,int errCode,std::string && errMsg)58 static void ThrowBusinessError(ani_env *env, int errCode, std::string &&errMsg)
59 {
60 LOGD("Begin ThrowBusinessError.");
61 static const char *errorClsName = "L@ohos/base/BusinessError;";
62 ani_class cls {};
63 if (ANI_OK != env->FindClass(errorClsName, &cls)) {
64 LOGE("find class BusinessError %{public}s failed", errorClsName);
65 return;
66 }
67 ani_method ctor;
68 if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", ":V", &ctor)) {
69 LOGE("find method BusinessError.constructor failed");
70 return;
71 }
72 ani_object errorObject;
73 if (ANI_OK != env->Object_New(cls, ctor, &errorObject)) {
74 LOGE("create BusinessError object failed");
75 return;
76 }
77 ani_string errMsgStr;
78 if (ANI_OK != env->String_NewUTF8(errMsg.c_str(), errMsg.size(), &errMsgStr)) {
79 LOGE("convert errMsg to ani_string failed");
80 return;
81 }
82 if (ANI_OK != env->Object_SetFieldByName_Double(errorObject, "code", static_cast<ani_double>(errCode))) {
83 LOGE("set error code failed");
84 return;
85 }
86 if (ANI_OK != env->Object_SetPropertyByName_Ref(errorObject, "message", errMsgStr)) {
87 LOGE("set error message failed");
88 return;
89 }
90 if (ANI_OK != env->ThrowError(static_cast<ani_error>(errorObject))) {
91 LOGE("throw error object failed");
92 }
93 return;
94 }
95
GetUriFromPath(ani_env * env,ani_string stringObj)96 static ani_string GetUriFromPath(ani_env *env, ani_string stringObj)
97 {
98 LOGD("Enter GetUriFromPath");
99 ani_string uriObj = nullptr;
100 std::string path = ParseObjToStr(env, stringObj);
101
102 std::string uri = CommonFunc::GetUriFromPath(path);
103 if (uri == "") {
104 LOGE("CommonFunc::GetUriFromPath failed!");
105 ThrowBusinessError(env, OHOS::FileManagement::LibN::E_PARAMS, "CommonFunc::GetUriFromPath failed!");
106 return uriObj;
107 }
108 LOGD("GetUriFromPath uri: %{public}s", uri.c_str());
109
110 ani_status status = env->String_NewUTF8(uri.c_str(), uri.size(), &uriObj);
111 if (status != ANI_OK) {
112 LOGE("String_NewUTF8 failed with status: %{public}d", status);
113 return nullptr;
114 }
115
116 return uriObj;
117 }
118
FileUriConstructor(ani_env * env,ani_object obj,ani_string stringObj)119 static void FileUriConstructor(ani_env *env, ani_object obj, ani_string stringObj)
120 {
121 LOGD("Enter FileUriConstructor");
122 std::string path = ParseObjToStr(env, stringObj);
123 if (path == "") {
124 LOGE("FileUriConstructor get path parameter failed!");
125 ThrowBusinessError(env, EINVAL, "Failed to get path");
126 return;
127 }
128 auto fileuriEntity = OHOS::FileManagement::CreateUniquePtr<ModuleFileUri::FileUriEntity>(path);
129 if (fileuriEntity == nullptr) {
130 LOGE("Failed to request heap memory.");
131 ThrowBusinessError(env, ENOMEM, "Failed to request heap memory.");
132 return;
133 }
134 StdSharedPtrHolder<ModuleFileUri::FileUriEntity> *holder =
135 new StdSharedPtrHolder<ModuleFileUri::FileUriEntity>(std::move(fileuriEntity));
136 if (holder == nullptr) {
137 return;
138 }
139
140 ani_namespace ns;
141 if (env->FindNamespace("L@ohos/file/fileuri/fileUri;", &ns) != ANI_OK) {
142 LOGE("Namespace L@ohos/file/fileuri/fileUri not found.");
143 delete holder;
144 ThrowBusinessError(env, EPERM, "Namespace L@ohos/file/fileuri/fileUri not found.");
145 return;
146 };
147
148 ani_class cls;
149 static const char *className = "LFileUri;";
150 if (env->Namespace_FindClass(ns, className, &cls) != ANI_OK) {
151 LOGE("Not found class LFileUri in Namespace L@ohos/file/fileuri/fileUri.");
152 delete holder;
153 ThrowBusinessError(env, EPERM, "Class LFileUri not found.");
154 return;
155 }
156
157 ani_method acquireObj;
158 if (ANI_OK != env->Class_FindMethod(cls, "acquireFileUriEntity", "J:V", &acquireObj)) {
159 LOGE("Not found method acquireFileUriEntity in class LFileUri.");
160 delete holder;
161 ThrowBusinessError(env, EPERM, "Method acquireFileUriEntity not found.");
162 return;
163 }
164
165 if (ANI_OK != env->Object_CallMethod_Void(obj, acquireObj, reinterpret_cast<ani_long>(holder))) {
166 LOGE("Call method acquireFileUriEntity failed.");
167 delete holder;
168 ThrowBusinessError(env, EPERM, "Call method acquireFileUriEntity failed.");
169 return;
170 }
171 }
172
ANI_Constructor(ani_vm * vm,uint32_t * result)173 ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result)
174 {
175 LOGD("Enter ANI_Constructor.");
176 ani_env *env;
177 if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env)) {
178 LOGE("Unsupported ANI_VERSION_1");
179 return ANI_ERROR;
180 }
181
182 static const char *nsName = "L@ohos/file/fileuri/fileUri;";
183 ani_namespace ns;
184 if (ANI_OK != env->FindNamespace(nsName, &ns)) {
185 LOGE("Not found namespace %{public}s.", nsName);
186 return ANI_NOT_FOUND;
187 }
188 std::array nsMethods = {
189 ani_native_function {"getUriFromPath", nullptr, reinterpret_cast<void *>(GetUriFromPath)},
190 };
191 if (ANI_OK != env->Namespace_BindNativeFunctions(ns, nsMethods.data(), nsMethods.size())) {
192 LOGE("Cannot bind native methods to namespace %{public}s.", nsName);
193 return ANI_ERROR;
194 };
195
196 static const char *className = "LFileUri;";
197 ani_class fileUriClass;
198 if (ANI_OK != env->Namespace_FindClass(ns, className, &fileUriClass)) {
199 LOGE("Not found class %{public}s in %{public}s.", nsName, nsName);
200 return ANI_NOT_FOUND;
201 }
202 std::array classMethods = {
203 ani_native_function {"<ctor>", "Lstd/core/String;:V", reinterpret_cast<void *>(FileUriConstructor)},
204 };
205 if (ANI_OK != env->Class_BindNativeMethods(fileUriClass, classMethods.data(), classMethods.size())) {
206 LOGE("Cannot bind native methods to class %{public}s.", className);
207 return ANI_ERROR;
208 };
209
210 ani_class cleanerCls;
211 if (ANI_OK != env->FindClass("L@ohos/file/fileuri/Cleaner;", &cleanerCls)) {
212 LOGE("Not found class @ohos/file/fileuri/Cleaner;.");
213 return ANI_NOT_FOUND;
214 }
215 NativePtrCleaner(env).Bind(cleanerCls);
216
217 *result = ANI_VERSION_1;
218 return ANI_OK;
219 }
220