• 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 #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