1 /*
2  * Copyright (c) 2022-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 
16 #include "n_val.h"
17 
18 #include <string>
19 
20 #include "file_utils.h"
21 #include "filemgmt_libhilog.h"
22 #include "n_error.h"
23 
24 namespace OHOS {
25 namespace FileManagement {
26 namespace LibN {
27 using namespace std;
28 
NVal(napi_env nEnv,napi_value nVal=nullptr)29 NVal::NVal(napi_env nEnv, napi_value nVal = nullptr) : env_(nEnv), val_(nVal) {}
30 
31 NVal::operator bool() const
32 {
33     return env_ && val_;
34 }
35 
TypeIs(napi_valuetype expType) const36 bool NVal::TypeIs(napi_valuetype expType) const
37 {
38     if (!*this) {
39         return false;
40     }
41     napi_valuetype valueType;
42     napi_typeof(env_, val_, &valueType);
43 
44     if (expType != valueType) {
45         return false;
46     }
47     return true;
48 }
49 
TypeIsError(bool checkErrno) const50 bool NVal::TypeIsError(bool checkErrno) const
51 {
52     if (!*this) {
53         return false;
54     }
55 
56     bool res = false;
57     napi_is_error(env_, val_, &res);
58 
59     return res;
60 }
61 
ToUTF8StringPath() const62 std::tuple<bool, std::unique_ptr<char[]>, size_t> NVal::ToUTF8StringPath() const
63 {
64     auto [succ, path, strLen] = ToUTF8String();
65     if (succ == false || std::strlen(path.get()) < strLen) {
66         return { false, nullptr, 0 };
67     }
68     return make_tuple(true, move(path), strLen);
69 }
70 
ToUTF8String() const71 tuple<bool, unique_ptr<char[]>, size_t> NVal::ToUTF8String() const
72 {
73     size_t strLen = 0;
74     napi_status status = napi_get_value_string_utf8(env_, val_, nullptr, -1, &strLen);
75     if (status != napi_ok) {
76         return { false, nullptr, 0 };
77     }
78     if (strLen == std::numeric_limits<size_t>::max()) {
79         HILOGE("string is too long");
80         return { false, nullptr, 0 };
81     }
82     size_t bufLen = strLen + 1;
83     auto str = CreateUniquePtr<char[]>(bufLen);
84     if (str == nullptr) {
85         return { false, nullptr, 0 };
86     }
87     status = napi_get_value_string_utf8(env_, val_, str.get(), bufLen, &strLen);
88     if (str == nullptr) {
89         return { false, nullptr, 0 };
90     }
91     return make_tuple(status == napi_ok, move(str), strLen);
92 }
93 
ToUTF8String(string defaultValue) const94 tuple<bool, unique_ptr<char[]>, size_t> NVal::ToUTF8String(string defaultValue) const
95 {
96     if (TypeIs(napi_undefined) || TypeIs(napi_function)) {
97         auto str = CreateUniquePtr<char[]>(defaultValue.size() + 1);
98         if (str == nullptr) {
99             return { false, nullptr, 0 };
100         }
101         copy(defaultValue.begin(), defaultValue.end(), str.get());
102         str[defaultValue.size()] = '\0';
103         return make_tuple(true, move(str), defaultValue.size());
104     }
105     return ToUTF8String();
106 }
107 
ToUTF16String() const108 tuple<bool, unique_ptr<char[]>, size_t> NVal::ToUTF16String() const
109 {
110 #ifdef FILE_SUBSYSTEM_DEBUG_LOCAL
111     size_t strLen = 0;
112     napi_status status = napi_get_value_string_utf16(env_, val_, nullptr, -1, &strLen);
113     if (status != napi_ok) {
114         return { false, nullptr, 0 };
115     }
116 
117     auto str = CreateUniquePtr<char16_t[]>(++strLen);
118     if (str == nullptr) {
119         return { false, nullptr, 0 };
120     }
121     status = napi_get_value_string_utf16(env_, val_, str.get(), strLen, nullptr);
122     if (status != napi_ok) {
123         return { false, nullptr, 0 };
124     }
125 
126     strLen = reinterpret_cast<char *>(str.get() + strLen) - reinterpret_cast<char *>(str.get());
127     auto strRet = unique_ptr<char[]>(reinterpret_cast<char *>(str.release()));
128     return {true, move(strRet), strLen};
129 #else
130     // Note that quickjs doesn't support utf16
131     return ToUTF8String();
132 #endif
133 }
134 
ToPointer() const135 tuple<bool, void *> NVal::ToPointer() const
136 {
137     void *res = nullptr;
138     napi_status status = napi_get_value_external(env_, val_, &res);
139     return make_tuple(status == napi_ok, res);
140 }
141 
ToBool() const142 tuple<bool, bool> NVal::ToBool() const
143 {
144     bool flag = false;
145     napi_status status = napi_get_value_bool(env_, val_, &flag);
146     return make_tuple(status == napi_ok, flag);
147 }
148 
ToBool(bool defaultValue) const149 tuple<bool, bool> NVal::ToBool(bool defaultValue) const
150 {
151     if (TypeIs(napi_undefined) || TypeIs(napi_function)) {
152         return make_tuple(true, defaultValue);
153     }
154     return ToBool();
155 }
156 
ToInt32() const157 tuple<bool, int32_t> NVal::ToInt32() const
158 {
159     int32_t res = 0;
160     napi_status status = napi_get_value_int32(env_, val_, &res);
161     return make_tuple(status == napi_ok, res);
162 }
163 
ToInt32(int32_t defaultValue) const164 tuple<bool, int32_t> NVal::ToInt32(int32_t defaultValue) const
165 {
166     if (TypeIs(napi_undefined) || TypeIs(napi_function)) {
167         return make_tuple(true, defaultValue);
168     }
169     return ToInt32();
170 }
171 
ToInt64() const172 tuple<bool, int64_t> NVal::ToInt64() const
173 {
174     int64_t res = 0;
175     napi_status status = napi_get_value_int64(env_, val_, &res);
176     return make_tuple(status == napi_ok, res);
177 }
178 
ToInt64(int64_t defaultValue) const179 tuple<bool, int64_t> NVal::ToInt64(int64_t defaultValue) const
180 {
181     if (TypeIs(napi_undefined) || TypeIs(napi_function)) {
182         return make_tuple(true, defaultValue);
183     }
184     return ToInt64();
185 }
186 
ToDouble() const187 tuple<bool, double> NVal::ToDouble() const
188 {
189     double res = 0;
190     napi_status status = napi_get_value_double(env_, val_, &res);
191     return make_tuple(status == napi_ok, res);
192 }
193 
ToUint32() const194 tuple<bool, uint32_t> NVal::ToUint32() const
195 {
196     uint32_t res = 0;
197     napi_status status = napi_get_value_uint32(env_, val_, &res);
198     return make_tuple(status == napi_ok, res);
199 }
200 
ToUint64() const201 tuple<bool, uint64_t, bool> NVal::ToUint64() const
202 {
203     uint64_t res = 0;
204     bool lossless = false;
205     napi_status status = napi_get_value_bigint_uint64(env_, val_, &res, &lossless);
206     return make_tuple(status == napi_ok, res, lossless);
207 }
208 
ToStringArray()209 tuple<bool, vector<string>, uint32_t> NVal::ToStringArray()
210 {
211     napi_status status;
212     uint32_t size = 0;
213     status = napi_get_array_length(env_, val_, &size);
214     vector<string> stringArray;
215     napi_value result;
216     for (uint32_t i = 0; i < size; i++) {
217         status = napi_get_element(env_, val_, i, &result);
218         auto [succ, str, ignore] = NVal(env_, result).ToUTF8String();
219         stringArray.push_back(string(str.get()));
220     }
221     return make_tuple(status == napi_ok, stringArray, size);
222 }
223 
ToArraybuffer() const224 tuple<bool, void *, size_t> NVal::ToArraybuffer() const
225 {
226     void *buf = nullptr;
227     size_t bufLen = 0;
228     bool status = napi_get_arraybuffer_info(env_, val_, &buf, &bufLen);
229     return make_tuple(status == napi_ok, buf, bufLen);
230 }
231 
ToTypedArray() const232 tuple<bool, void *, size_t> NVal::ToTypedArray() const
233 {
234     napi_typedarray_type type;
235     napi_value in_array_buffer = nullptr;
236     size_t byte_offset;
237     size_t length;
238     void *data = nullptr;
239     napi_status status =
240         napi_get_typedarray_info(env_, val_, &type, &length, (void **)&data, &in_array_buffer, &byte_offset);
241     return make_tuple(status == napi_ok, data, length);
242 }
243 
HasProp(string propName) const244 bool NVal::HasProp(string propName) const
245 {
246     bool res = false;
247 
248     if (!env_ || !val_ || !TypeIs(napi_object)) {
249         return false;
250     }
251 
252     napi_status status = napi_has_named_property(env_, val_, propName.c_str(), &res);
253     return (status == napi_ok) && res;
254 }
255 
256 #ifdef WIN_PLATFORM
GetPropValue(string propName) const257 NVal NVal::GetPropValue(string propName) const
258 #else
259 NVal NVal::GetProp(string propName) const
260 #endif
261 {
262     if (!HasProp(propName)) {
263         return {env_, nullptr};
264     }
265 
266     napi_value prop = nullptr;
267     napi_status status = napi_get_named_property(env_, val_, propName.c_str(), &prop);
268     if (status != napi_ok) {
269         return {env_, nullptr};
270     }
271     return NVal(env_, prop);
272 }
273 
AddProp(vector<napi_property_descriptor> && propVec) const274 bool NVal::AddProp(vector<napi_property_descriptor> &&propVec) const
275 {
276     if (!TypeIs(napi_valuetype::napi_object)) {
277         HILOGE("INNER BUG. Prop should only be added to objects");
278         return false;
279     }
280 
281     napi_status status = napi_define_properties(env_, val_, propVec.size(), propVec.data());
282     if (status != napi_ok) {
283         HILOGE("INNER BUG. Cannot define properties because of %{public}d", status);
284         return false;
285     }
286     return true;
287 }
288 
AddProp(string propName,napi_value val) const289 bool NVal::AddProp(string propName, napi_value val) const
290 {
291     if (!TypeIs(napi_valuetype::napi_object) || HasProp(propName)) {
292         HILOGE("INNER BUG. Prop should only be added to objects");
293         return false;
294     }
295 
296     napi_status status = napi_set_named_property(env_, val_, propName.c_str(), val);
297     if (status != napi_ok) {
298         HILOGE("INNER BUG. Cannot set named property because of %{public}d", status);
299         return false;
300     }
301     return true;
302 }
303 
CreateUndefined(napi_env env)304 NVal NVal::CreateUndefined(napi_env env)
305 {
306     napi_value res = nullptr;
307     napi_get_undefined(env, &res);
308     return {env, res};
309 }
310 
CreateBigInt64(napi_env env,int64_t val)311 NVal NVal::CreateBigInt64(napi_env env, int64_t val)
312 {
313     napi_value res = nullptr;
314     napi_create_bigint_int64(env, val, &res);
315     return { env, res };
316 }
317 
CreateInt64(napi_env env,int64_t val)318 NVal NVal::CreateInt64(napi_env env, int64_t val)
319 {
320     napi_value res = nullptr;
321     napi_create_int64(env, val, &res);
322     return {env, res};
323 }
324 
CreateInt32(napi_env env,int32_t val)325 NVal NVal::CreateInt32(napi_env env, int32_t val)
326 {
327     napi_value res = nullptr;
328     napi_create_int32(env, val, &res);
329     return {env, res};
330 }
331 
CreateUint32(napi_env env,int32_t val)332 NVal NVal::CreateUint32(napi_env env, int32_t val)
333 {
334     napi_value res = nullptr;
335     napi_create_uint32(env, val, &res);
336     return {env, res};
337 }
338 
CreateObject(napi_env env)339 NVal NVal::CreateObject(napi_env env)
340 {
341     napi_value res = nullptr;
342     napi_create_object(env, &res);
343     return {env, res};
344 }
345 
CreateBool(napi_env env,bool val)346 NVal NVal::CreateBool(napi_env env, bool val)
347 {
348     napi_value res = nullptr;
349     napi_get_boolean(env, val, &res);
350     return {env, res};
351 }
352 
CreateUTF8String(napi_env env,std::string str)353 NVal NVal::CreateUTF8String(napi_env env, std::string str)
354 {
355     napi_value res = nullptr;
356     napi_create_string_utf8(env, str.c_str(), str.length(), &res);
357     return {env, res};
358 }
359 
CreateUTF8String(napi_env env,const char * str,ssize_t len)360 NVal NVal::CreateUTF8String(napi_env env, const char *str, ssize_t len)
361 {
362     napi_value res = nullptr;
363     napi_create_string_utf8(env, str, len, &res);
364     return {env, res};
365 }
366 
CreateUint8Array(napi_env env,void * buf,size_t bufLen)367 NVal NVal::CreateUint8Array(napi_env env, void *buf, size_t bufLen)
368 {
369     napi_value output_buffer = nullptr;
370     napi_create_external_arraybuffer(
371         env, buf, bufLen, [](napi_env env, void *finalize_data, void *finalize_hint) { free(finalize_data); }, NULL,
372         &output_buffer);
373     napi_value output_array = nullptr;
374     napi_create_typedarray(env, napi_uint8_array, bufLen, output_buffer, 0, &output_array);
375     return {env, output_array};
376 }
377 
CreateArrayString(napi_env env,vector<string> strs)378 NVal NVal::CreateArrayString(napi_env env, vector<string> strs)
379 {
380     napi_value res = nullptr;
381     napi_create_array(env, &res);
382     for (size_t i = 0; i < strs.size(); i++) {
383         napi_value filename;
384         napi_create_string_utf8(env, strs[i].c_str(), strs[i].length(), &filename);
385         napi_set_element(env, res, i, filename);
386     }
387     return {env, res};
388 }
389 
CreateArrayBuffer(napi_env env,size_t len)390 tuple<NVal, void *> NVal::CreateArrayBuffer(napi_env env, size_t len)
391 {
392     napi_value val;
393     void *buf = nullptr;
394     napi_create_arraybuffer(env, len, &buf, &val);
395     return {{env, val}, {buf}};
396 }
397 
DeclareNapiProperty(const char * name,napi_value val)398 napi_property_descriptor NVal::DeclareNapiProperty(const char *name, napi_value val)
399 {
400     return {(name), nullptr, nullptr, nullptr, nullptr, val, napi_default, nullptr};
401 }
402 
DeclareNapiStaticProperty(const char * name,napi_value val)403 napi_property_descriptor NVal::DeclareNapiStaticProperty(const char *name, napi_value val)
404 {
405     return {(name), nullptr, nullptr, nullptr, nullptr, val, napi_static, nullptr};
406 }
407 
DeclareNapiFunction(const char * name,napi_callback func)408 napi_property_descriptor NVal::DeclareNapiFunction(const char *name, napi_callback func)
409 {
410     return {(name), nullptr, (func), nullptr, nullptr, nullptr, napi_default, nullptr};
411 }
412 
DeclareNapiStaticFunction(const char * name,napi_callback func)413 napi_property_descriptor NVal::DeclareNapiStaticFunction(const char *name, napi_callback func)
414 {
415     return {(name), nullptr, (func), nullptr, nullptr, nullptr, napi_static, nullptr};
416 }
417 
DeclareNapiGetter(const char * name,napi_callback getter)418 napi_property_descriptor NVal::DeclareNapiGetter(const char *name, napi_callback getter)
419 {
420     return {(name), nullptr, nullptr, (getter), nullptr, nullptr, napi_default, nullptr};
421 }
422 
DeclareNapiSetter(const char * name,napi_callback setter)423 napi_property_descriptor NVal::DeclareNapiSetter(const char *name, napi_callback setter)
424 {
425     return {(name), nullptr, nullptr, nullptr, (setter), nullptr, napi_default, nullptr};
426 }
427 
DeclareNapiGetterSetter(const char * name,napi_callback getter,napi_callback setter)428 napi_property_descriptor NVal::DeclareNapiGetterSetter(const char *name, napi_callback getter, napi_callback setter)
429 {
430     return {(name), nullptr, nullptr, (getter), (setter), nullptr, napi_default, nullptr};
431 }
432 } // namespace LibN
433 } // namespace FileManagement
434 } // namespace OHOS
435