1 /*
2 * Copyright (c) 2023 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 #include "read_lines.h"
16
17 #include <unistd.h>
18
19 #include "class_readeriterator/readeriterator_entity.h"
20 #include "class_readeriterator/readeriterator_n_exporter.h"
21 #include "common_func.h"
22 #include "file_utils.h"
23 #include "filemgmt_libhilog.h"
24 #include "rust_file.h"
25
26 namespace OHOS {
27 namespace FileManagement {
28 namespace ModuleFileIO {
29 using namespace std;
30 using namespace OHOS::FileManagement::LibN;
31
CheckOptionArg(napi_env env,napi_value argOption)32 static int CheckOptionArg(napi_env env, napi_value argOption)
33 {
34 NVal option(env, argOption);
35 if (option.HasProp("encoding")) {
36 auto [succ, encoding, ignore] = option.GetProp("encoding").ToUTF8String("utf-8");
37 string_view encodingStr(encoding.get());
38 if (!succ || encodingStr != "utf-8") {
39 return EINVAL;
40 }
41 }
42
43 return ERRNO_NOERR;
44 }
45
GetFileSize(const string & path,int64_t & offset)46 static int GetFileSize(const string &path, int64_t &offset)
47 {
48 std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> stat_req = {
49 new (std::nothrow) uv_fs_t, CommonFunc::fs_req_cleanup };
50 if (!stat_req) {
51 HILOGE("Failed to request heap memory.");
52 return ENOMEM;
53 }
54
55 int ret = uv_fs_stat(nullptr, stat_req.get(), path.c_str(), nullptr);
56 if (ret < 0) {
57 HILOGE("Failed to get file stat by path");
58 return ret;
59 }
60
61 offset = static_cast<int64_t>(stat_req->statbuf.st_size);
62 return ERRNO_NOERR;
63 }
64
InstantiateReaderIterator(napi_env env,void * iterator,int64_t offset)65 static NVal InstantiateReaderIterator(napi_env env, void *iterator, int64_t offset)
66 {
67 if (iterator == nullptr) {
68 HILOGE("Invalid argument iterator");
69 NError(EINVAL).ThrowErr(env);
70 return NVal();
71 }
72
73 napi_value objReaderIterator = NClass::InstantiateClass(env, ReaderIteratorNExporter::className_, {});
74 if (!objReaderIterator) {
75 HILOGE("Failed to instantiate class ReaderIterator");
76 NError(UNKROWN_ERR).ThrowErr(env);
77 return NVal();
78 }
79
80 auto readerIteratorEntity = NClass::GetEntityOf<ReaderIteratorEntity>(env, objReaderIterator);
81 if (!readerIteratorEntity) {
82 HILOGE("Failed to get readerIteratorEntity");
83 NError(UNKROWN_ERR).ThrowErr(env);
84 return NVal();
85 }
86
87 readerIteratorEntity->iterator = iterator;
88 readerIteratorEntity->offset = offset;
89 return { env, objReaderIterator };
90 }
91
92 struct ReaderIteratorArg {
93 void *iterator = nullptr;
94 int64_t offset = 0;
95 };
96
AsyncExec(ReaderIteratorArg & readerIterator,const string & pathStr)97 static NError AsyncExec(ReaderIteratorArg &readerIterator, const string &pathStr)
98 {
99 readerIterator.iterator = ::ReaderIterator(pathStr.c_str());
100 if (readerIterator.iterator == nullptr) {
101 HILOGE("Failed to read lines of the file, error: %{public}d", errno);
102 return NError(errno);
103 }
104 int ret = GetFileSize(pathStr, readerIterator.offset);
105 if (ret < 0) {
106 HILOGE("Failed to get size of the file");
107 return NError(ret);
108 }
109
110 return NError(ERRNO_NOERR);
111 }
112
Async(napi_env env,napi_callback_info info)113 napi_value ReadLines::Async(napi_env env, napi_callback_info info)
114 {
115 NFuncArg funcArg(env, info);
116 if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) {
117 HILOGE("Number of arguments unmatched");
118 NError(EINVAL).ThrowErr(env);
119 return nullptr;
120 }
121
122 auto [succPath, path, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8StringPath();
123 if (!succPath) {
124 HILOGE("Invalid path from JS first argument");
125 NError(EINVAL).ThrowErr(env);
126 return nullptr;
127 }
128
129 if (funcArg.GetArgc() >= NARG_CNT::TWO) {
130 int ret = CheckOptionArg(env, funcArg[NARG_POS::SECOND]);
131 if (ret) {
132 HILOGE("Invalid option.encoding parameter");
133 NError(ret).ThrowErr(env);
134 return nullptr;
135 }
136 }
137
138 auto arg = CreateSharedPtr<ReaderIteratorArg>();
139 if (arg == nullptr) {
140 HILOGE("Failed to request heap memory.");
141 NError(ENOMEM).ThrowErr(env);
142 return nullptr;
143 }
144 auto cbExec = [arg, pathStr = string(path.get())]() -> NError {
145 return AsyncExec(*arg, pathStr);
146 };
147
148 auto cbCompl = [arg](napi_env env, NError err) -> NVal {
149 if (err) {
150 return { env, err.GetNapiErr(env) };
151 }
152 return InstantiateReaderIterator(env, arg->iterator, arg->offset);
153 };
154
155 NVal thisVar(env, funcArg.GetThisVar());
156 if (funcArg.GetArgc() == NARG_CNT::ONE || (funcArg.GetArgc() == NARG_CNT::TWO &&
157 !NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_function))) {
158 return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_READLINES_NAME, cbExec, cbCompl).val_;
159 } else {
160 NVal cb(env, funcArg[((funcArg.GetArgc() == NARG_CNT::TWO) ? NARG_POS::SECOND : NARG_POS::THIRD)]);
161 return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_READLINES_NAME, cbExec, cbCompl).val_;
162 }
163 }
164
Sync(napi_env env,napi_callback_info info)165 napi_value ReadLines::Sync(napi_env env, napi_callback_info info)
166 {
167 NFuncArg funcArg(env, info);
168 if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) {
169 HILOGE("Number of arguments unmatched");
170 NError(EINVAL).ThrowErr(env);
171 return nullptr;
172 }
173
174 auto [succPath, path, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8StringPath();
175 if (!succPath) {
176 HILOGE("Invalid path from JS first argument");
177 NError(EINVAL).ThrowErr(env);
178 return nullptr;
179 }
180
181 if (funcArg.GetArgc() == NARG_CNT::TWO) {
182 int ret = CheckOptionArg(env, funcArg[NARG_POS::SECOND]);
183 if (ret) {
184 HILOGE("Invalid option.encoding parameter");
185 NError(ret).ThrowErr(env);
186 return nullptr;
187 }
188 }
189
190 auto iterator = ::ReaderIterator(path.get());
191 if (iterator == nullptr) {
192 HILOGE("Failed to read lines of the file, error: %{public}d", errno);
193 NError(errno).ThrowErr(env);
194 return nullptr;
195 }
196
197 int64_t offset = 0;
198 int ret = GetFileSize(path.get(), offset);
199 if (ret != 0) {
200 HILOGE("Failed to get size of the file");
201 return nullptr;
202 }
203
204 return InstantiateReaderIterator(env, iterator, offset).val_;
205 }
206
207 } // ModuleFileIO
208 } // FileManagement
209 } // OHOS