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 "stream_ani.h"
17
18 #include <optional>
19 #include <string>
20
21 #include "ani_helper.h"
22 #include "ani_signature.h"
23 #include "error_handler.h"
24 #include "filemgmt_libhilog.h"
25 #include "fs_stream.h"
26 #include "fs_utils.h"
27 #include "type_converter.h"
28
29 namespace OHOS {
30 namespace FileManagement {
31 namespace ModuleFileIO {
32 namespace ANI {
33 using namespace std;
34 using namespace OHOS::FileManagement::ModuleFileIO;
35 using namespace OHOS::FileManagement::ModuleFileIO::ANI::AniSignature;
36
ToReadOptions(ani_env * env,ani_object obj)37 static tuple<bool, optional<ReadOptions>> ToReadOptions(ani_env *env, ani_object obj)
38 {
39 ReadOptions options;
40 ani_boolean isUndefined;
41 env->Reference_IsUndefined(obj, &isUndefined);
42 if (isUndefined) {
43 return { true, nullopt };
44 }
45
46 auto [succOffset, offset] = AniHelper::ParseInt64Option(env, obj, "offset");
47 if (!succOffset) {
48 HILOGE("Illegal option.offset parameter");
49 return { false, nullopt };
50 }
51 options.offset = offset;
52
53 auto [succLength, length] = AniHelper::ParseInt64Option(env, obj, "length");
54 if (!succLength) {
55 HILOGE("Illegal option.length parameter");
56 return { false, nullopt };
57 }
58 options.length = length;
59 return { true, make_optional<ReadOptions>(move(options)) };
60 }
61
ToWriteOptions(ani_env * env,ani_object obj)62 static tuple<bool, optional<WriteOptions>> ToWriteOptions(ani_env *env, ani_object obj)
63 {
64 WriteOptions options;
65 ani_boolean isUndefined;
66 env->Reference_IsUndefined(obj, &isUndefined);
67 if (isUndefined) {
68 return { true, nullopt };
69 }
70
71 auto [succOffset, offset] = AniHelper::ParseInt64Option(env, obj, "offset");
72 if (!succOffset) {
73 HILOGE("Illegal option.offset parameter");
74 return { false, nullopt };
75 }
76 options.offset = offset;
77
78 auto [succLength, length] = AniHelper::ParseInt64Option(env, obj, "length");
79 if (!succLength) {
80 HILOGE("Illegal option.length parameter");
81 return { false, nullopt };
82 }
83 options.length = length;
84
85 auto [succEncoding, encoding] = AniHelper::ParseEncoding(env, obj);
86 if (!succEncoding) {
87 HILOGE("Illegal option.encoding parameter");
88 return { false, nullopt };
89 }
90 options.encoding = encoding;
91 return { true, make_optional<WriteOptions>(move(options)) };
92 }
93
ParseStringBuffer(ani_env * env,const ani_object & buf)94 static std::tuple<bool, ani_string> ParseStringBuffer(ani_env *env, const ani_object &buf)
95 {
96 auto classDesc = BuiltInTypes::String::classDesc.c_str();
97 ani_class cls;
98 env->FindClass(classDesc, &cls);
99
100 ani_boolean isString;
101 env->Object_InstanceOf(buf, cls, &isString);
102 if (!isString) {
103 HILOGE("Object_InstanceOf is failed");
104 return { false, {} };
105 }
106 auto result = static_cast<ani_string>(buf);
107 return { true, std::move(result) };
108 }
109
ParseArrayBuffer(ani_env * env,const ani_object & buf)110 static std::tuple<bool, ani_arraybuffer> ParseArrayBuffer(ani_env *env, const ani_object &buf)
111 {
112 auto classDesc = BuiltInTypes::ArrayBuffer::classDesc.c_str();
113 ani_class cls;
114 env->FindClass(classDesc, &cls);
115
116 ani_boolean isArrayBuffer;
117 env->Object_InstanceOf(buf, cls, &isArrayBuffer);
118 if (!isArrayBuffer) {
119 return { false, {} };
120 }
121 auto result = static_cast<ani_arraybuffer>(buf);
122 return { true, std::move(result) };
123 }
124
Unwrap(ani_env * env,ani_object object)125 static FsStream *Unwrap(ani_env *env, ani_object object)
126 {
127 ani_long nativePtr;
128 auto ret = env->Object_GetFieldByName_Long(object, "nativePtr", &nativePtr);
129 if (ret != ANI_OK) {
130 HILOGE("Unwrap fsFile err: %{private}d", ret);
131 return nullptr;
132 }
133 uintptr_t ptrValue = static_cast<uintptr_t>(nativePtr);
134 FsStream *stream = reinterpret_cast<FsStream *>(ptrValue);
135 return stream;
136 }
137
Close(ani_env * env,ani_object object)138 void StreamAni::Close(ani_env *env, [[maybe_unused]] ani_object object)
139 {
140 auto fsStream = Unwrap(env, object);
141 if (fsStream == nullptr) {
142 HILOGE("Cannot unwrap fsStream!");
143 ErrorHandler::Throw(env, EINVAL);
144 return;
145 }
146
147 auto ret = fsStream->Close();
148 if (!ret.IsSuccess()) {
149 HILOGE("Cannot close fsStream!");
150 const auto &err = ret.GetError();
151 ErrorHandler::Throw(env, err);
152 return;
153 }
154 }
155
Flush(ani_env * env,ani_object object)156 void StreamAni::Flush(ani_env *env, [[maybe_unused]] ani_object object)
157 {
158 auto fsStream = Unwrap(env, object);
159 if (fsStream == nullptr) {
160 HILOGE("Cannot unwrap fsStream!");
161 ErrorHandler::Throw(env, EINVAL);
162 return;
163 }
164
165 auto ret = fsStream->Flush();
166 if (!ret.IsSuccess()) {
167 HILOGE("Cannot flush fsStream!");
168 const auto &err = ret.GetError();
169 ErrorHandler::Throw(env, err);
170 return;
171 }
172 }
173
Write(ani_env * env,ani_object object,ani_object buf,ani_object options)174 ani_double StreamAni::Write(ani_env *env, [[maybe_unused]] ani_object object, ani_object buf, ani_object options)
175 {
176 auto fsStream = Unwrap(env, object);
177 if (fsStream == nullptr) {
178 HILOGE("Cannot unwrap fsStream!");
179 return -1;
180 }
181
182 auto [succOp, op] = ToWriteOptions(env, options);
183 if (!succOp) {
184 HILOGE("Failed to resolve options!");
185 return -1;
186 }
187
188 auto [isString, stringBuffer] = ParseStringBuffer(env, buf);
189 if (isString) {
190 auto [succBuf, buffer] = TypeConverter::ToUTF8String(env, stringBuffer);
191 if (!succBuf) {
192 HILOGE("Failed to resolve stringBuffer!");
193 ErrorHandler::Throw(env, EINVAL);
194 return -1;
195 }
196 auto ret = fsStream->Write(buffer, op);
197 if (!ret.IsSuccess()) {
198 HILOGE("write string failed!");
199 const auto &err = ret.GetError();
200 ErrorHandler::Throw(env, err);
201 return -1;
202 }
203 return ret.GetData().value();
204 }
205
206 auto [isArrayBuffer, arrayBuffer] = ParseArrayBuffer(env, buf);
207 if (isArrayBuffer) {
208 auto [succBuf, buffer] = TypeConverter::ToArrayBuffer(env, arrayBuffer);
209 if (!succBuf) {
210 HILOGE("Failed to resolve arrayBuffer!");
211 ErrorHandler::Throw(env, EINVAL);
212 return -1;
213 }
214 auto ret = fsStream->Write(buffer, op);
215 if (!ret.IsSuccess()) {
216 HILOGE("write buffer failed!");
217 const auto &err = ret.GetError();
218 ErrorHandler::Throw(env, err);
219 return -1;
220 }
221 return static_cast<double>(ret.GetData().value());
222 }
223
224 HILOGE("Unsupported buffer type!");
225 ErrorHandler::Throw(env, EINVAL);
226 return -1;
227 }
228
Read(ani_env * env,ani_object object,ani_arraybuffer buffer,ani_object options)229 ani_double StreamAni::Read(ani_env *env, [[maybe_unused]] ani_object object, ani_arraybuffer buffer, ani_object options)
230 {
231 auto fsStream = Unwrap(env, object);
232 if (fsStream == nullptr) {
233 HILOGE("Cannot unwrap fsStream!");
234 ErrorHandler::Throw(env, EINVAL);
235 return -1;
236 }
237
238 auto [succBuf, arrayBuffer] = TypeConverter::ToArrayBuffer(env, buffer);
239 if (!succBuf) {
240 HILOGE("Failed to resolve arrayBuffer!");
241 ErrorHandler::Throw(env, EINVAL);
242 return -1;
243 }
244
245 auto [succOp, op] = ToReadOptions(env, options);
246 if (!succOp) {
247 HILOGE("Failed to resolve options!");
248 ErrorHandler::Throw(env, EINVAL);
249 return -1;
250 }
251
252 auto ret = fsStream->Read(arrayBuffer, op);
253 if (!ret.IsSuccess()) {
254 HILOGE("write buffer failed!");
255 const auto &err = ret.GetError();
256 ErrorHandler::Throw(env, err);
257 return -1;
258 }
259 return static_cast<double>(ret.GetData().value());
260 }
261
Seek(ani_env * env,ani_object object,ani_double offset,ani_object whence)262 ani_double StreamAni::Seek(ani_env *env, [[maybe_unused]] ani_object object, ani_double offset, ani_object whence)
263 {
264 auto fsStream = Unwrap(env, object);
265 if (fsStream == nullptr) {
266 HILOGE("Cannot unwrap fsStream!");
267 ErrorHandler::Throw(env, EINVAL);
268 return -1;
269 }
270
271 auto [succ, typeOpt] = TypeConverter::ToOptionalInt32(env, whence);
272 if (!succ) {
273 HILOGE("Invalied whence type");
274 ErrorHandler::Throw(env, EINVAL);
275 return -1;
276 }
277
278 auto ret = fsStream->Seek(static_cast<int64_t>(offset), typeOpt);
279 if (!ret.IsSuccess()) {
280 HILOGE("seek failed!");
281 const auto &err = ret.GetError();
282 ErrorHandler::Throw(env, err);
283 return -1;
284 }
285 return static_cast<double>(ret.GetData().value());
286 }
287
288 } // namespace ANI
289 } // namespace ModuleFileIO
290 } // namespace FileManagement
291 } // namespace OHOS