• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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