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
24namespace OHOS {
25namespace FileManagement {
26namespace LibN {
27using namespace std;
28
29NVal::NVal(napi_env nEnv, napi_value nVal = nullptr) : env_(nEnv), val_(nVal) {}
30
31NVal::operator bool() const
32{
33    return env_ && val_;
34}
35
36bool 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
50bool 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
62std::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
71tuple<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
94tuple<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
108tuple<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
135tuple<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
142tuple<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
149tuple<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
157tuple<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
164tuple<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
172tuple<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
179tuple<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
187tuple<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
194tuple<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
201tuple<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
209tuple<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
224tuple<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
232tuple<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
244bool 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
257NVal NVal::GetPropValue(string propName) const
258#else
259NVal 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
274bool 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
289bool 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
304NVal NVal::CreateUndefined(napi_env env)
305{
306    napi_value res = nullptr;
307    napi_get_undefined(env, &res);
308    return {env, res};
309}
310
311NVal 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
318NVal 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
325NVal 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
332NVal 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
339NVal NVal::CreateObject(napi_env env)
340{
341    napi_value res = nullptr;
342    napi_create_object(env, &res);
343    return {env, res};
344}
345
346NVal 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
353NVal 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
360NVal 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
367NVal 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
378NVal 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
390tuple<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
398napi_property_descriptor NVal::DeclareNapiProperty(const char *name, napi_value val)
399{
400    return {(name), nullptr, nullptr, nullptr, nullptr, val, napi_default, nullptr};
401}
402
403napi_property_descriptor NVal::DeclareNapiStaticProperty(const char *name, napi_value val)
404{
405    return {(name), nullptr, nullptr, nullptr, nullptr, val, napi_static, nullptr};
406}
407
408napi_property_descriptor NVal::DeclareNapiFunction(const char *name, napi_callback func)
409{
410    return {(name), nullptr, (func), nullptr, nullptr, nullptr, napi_default, nullptr};
411}
412
413napi_property_descriptor NVal::DeclareNapiStaticFunction(const char *name, napi_callback func)
414{
415    return {(name), nullptr, (func), nullptr, nullptr, nullptr, napi_static, nullptr};
416}
417
418napi_property_descriptor NVal::DeclareNapiGetter(const char *name, napi_callback getter)
419{
420    return {(name), nullptr, nullptr, (getter), nullptr, nullptr, napi_default, nullptr};
421}
422
423napi_property_descriptor NVal::DeclareNapiSetter(const char *name, napi_callback setter)
424{
425    return {(name), nullptr, nullptr, nullptr, (setter), nullptr, napi_default, nullptr};
426}
427
428napi_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