1 /*
2 * Copyright (c) 2021 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 "common_func.h"
17
18 #include <dirent.h>
19 #include <fcntl.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23
24 #include "../common/log.h"
25 #include "../common/napi/n_class.h"
26 #include "../common/napi/n_func_arg.h"
27 #include "../common/uni_error.h"
28
29 namespace OHOS {
30 namespace DistributedFS {
31 namespace ModuleFileIO {
32 using namespace std;
33
GetActualBuf(napi_env env,void * rawBuf,int64_t bufLen,NVal op)34 static tuple<bool, void *> GetActualBuf(napi_env env, void *rawBuf, int64_t bufLen, NVal op)
35 {
36 bool succ = false;
37 void *realBuf = nullptr;
38
39 if (op.HasProp("offset")) {
40 int64_t opOffset;
41 tie(succ, opOffset) = op.GetProp("offset").ToInt64();
42 if (!succ || opOffset < 0) {
43 UniError(EINVAL).ThrowErr(env, "Invalid option.offset, positive integer is desired");
44 return { false, nullptr };
45 } else if (opOffset > bufLen) {
46 UniError(EINVAL).ThrowErr(env, "Invalid option.offset, buffer limit exceeded");
47 return { false, nullptr };
48 } else {
49 realBuf = static_cast<uint8_t *>(rawBuf) + opOffset;
50 }
51 } else {
52 realBuf = rawBuf;
53 }
54
55 return { true, realBuf };
56 }
57
GetActualLen(napi_env env,int64_t bufLen,int64_t bufOff,NVal op)58 static tuple<bool, size_t> GetActualLen(napi_env env, int64_t bufLen, int64_t bufOff, NVal op)
59 {
60 bool succ = false;
61 int64_t retLen;
62
63 if (op.HasProp("length")) {
64 int64_t opLength;
65 tie(succ, opLength) = op.GetProp("length").ToInt64();
66 if (!succ) {
67 UniError(EINVAL).ThrowErr(env, "Invalid option.length, expect integer");
68 return { false, 0 };
69 }
70 if (opLength < 0) {
71 retLen = bufLen - bufOff;
72 } else if (opLength + bufOff > bufLen) {
73 UniError(EINVAL).ThrowErr(env, "Invalid option.length, buffer limit exceeded");
74 return { false, 0 };
75 } else {
76 retLen = opLength;
77 }
78 } else {
79 retLen = bufLen - bufOff;
80 }
81
82 return { true, retLen };
83 }
84
GetReadArg(napi_env env,napi_value readBuf,napi_value option)85 tuple<bool, void *, int64_t, bool, int64_t> CommonFunc::GetReadArg(napi_env env, napi_value readBuf, napi_value option)
86 {
87 bool succ = false;
88 void *retBuf = nullptr;
89 int64_t retLen;
90 bool posAssigned = false;
91 int64_t position;
92
93 NVal txt(env, readBuf);
94 void *buf = nullptr;
95 int64_t bufLen;
96 tie(succ, buf, bufLen) = txt.ToArraybuffer();
97 if (!succ) {
98 UniError(EINVAL).ThrowErr(env, "Invalid read buffer, expect arraybuffer");
99 return { false, nullptr, 0, posAssigned, position };
100 }
101
102 NVal op = NVal(env, option);
103 tie(succ, retBuf) = GetActualBuf(env, buf, bufLen, op);
104 if (!succ) {
105 return { false, nullptr, 0, posAssigned, position };
106 }
107
108 int64_t bufOff = static_cast<uint8_t *>(retBuf) - static_cast<uint8_t *>(buf);
109 tie(succ, retLen) = GetActualLen(env, bufLen, bufOff, op);
110 if (!succ) {
111 return { false, nullptr, 0, posAssigned, position };
112 }
113
114 tie(succ, position) = op.GetProp("position").ToInt64();
115 if (succ && position >= 0) {
116 posAssigned = true;
117 }
118 return { true, retBuf, retLen, posAssigned, position };
119 }
120
DecodeString(napi_env env,NVal jsStr,NVal encoding)121 static tuple<bool, unique_ptr<char[]>, int64_t> DecodeString(napi_env env, NVal jsStr, NVal encoding)
122 {
123 unique_ptr<char[]> buf;
124 if (!jsStr.TypeIs(napi_string)) {
125 return { false, nullptr, 0 };
126 }
127
128 bool succ = false;
129 if (!encoding) {
130 return jsStr.ToUTF8String();
131 }
132
133 unique_ptr<char[]> encodingBuf;
134 tie(succ, encodingBuf, ignore) = encoding.ToUTF8String();
135 if (!succ) {
136 return { false, nullptr, 0 };
137 }
138 string encodingStr(encodingBuf.release());
139 if (encodingStr == "utf-8") {
140 return jsStr.ToUTF8String();
141 } else if (encodingStr == "utf-16") {
142 return jsStr.ToUTF16String();
143 } else {
144 return { false, nullptr, 0 };
145 }
146 }
147
148 // Is everthing ok? Do we need to free memory? What's the three args required by fwrite? Where to start writing?
GetWriteArg(napi_env env,napi_value argWBuf,napi_value argOption)149 tuple<bool, unique_ptr<char[]>, void *, int64_t, bool, int64_t> CommonFunc::GetWriteArg(napi_env env,
150 napi_value argWBuf,
151 napi_value argOption)
152 {
153 void *retBuf = nullptr;
154 int64_t retLen;
155 bool hasPos = false;
156 int64_t retPos;
157
158 /* To get write buffer */
159 bool succ = false;
160 void *buf = nullptr;
161 int64_t bufLen;
162 NVal op(env, argOption);
163 NVal jsBuffer(env, argWBuf);
164 unique_ptr<char[]> bufferGuard;
165 tie(succ, bufferGuard, bufLen) = DecodeString(env, jsBuffer, op.GetProp("encoding"));
166 if (!succ) {
167 tie(succ, buf, bufLen) = NVal(env, argWBuf).ToArraybuffer();
168 if (!succ) {
169 UniError(EINVAL).ThrowErr(env, "Illegal write buffer or encoding");
170 return { false, nullptr, nullptr, 0, hasPos, retPos };
171 }
172 } else {
173 buf = bufferGuard.get();
174 }
175
176 tie(succ, retBuf) = GetActualBuf(env, buf, bufLen, op);
177 if (!succ) {
178 return { false, nullptr, nullptr, 0, hasPos, retPos };
179 }
180
181 int64_t bufOff = static_cast<uint8_t *>(retBuf) - static_cast<uint8_t *>(buf);
182 tie(succ, retLen) = GetActualLen(env, bufLen, bufOff, op);
183 if (!succ) {
184 return { false, nullptr, nullptr, 0, hasPos, retPos };
185 }
186
187 /* To parse options - Where to begin writing */
188 if (op.HasProp("position")) {
189 int32_t position = 0;
190 tie(succ, position) = op.GetProp("position").ToInt32();
191 if (!succ || position < 0) {
192 UniError(EINVAL).ThrowErr(env, "option.position shall be positive number");
193 return { false, nullptr, nullptr, 0, hasPos, retPos };
194 }
195 hasPos = true;
196 retPos = position;
197 } else {
198 retPos = INVALID_POSITION;
199 }
200 return { true, move(bufferGuard), retBuf, retLen, hasPos, retPos };
201 }
202 } // namespace ModuleFileIO
203 } // namespace DistributedFS
204 } // namespace OHOS
205