1 /*
2  * Copyright (c) 2021-2022 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 "../log.h"
21 #include "../uni_error.h"
22 
23 namespace OHOS {
24 namespace DistributedFS {
25 using namespace std;
26 
NVal(napi_env nEnv,napi_value nVal=nullptr)27 NVal::NVal(napi_env nEnv, napi_value nVal = nullptr) : env_(nEnv), val_(nVal) {}
28 
29 NVal::operator bool() const
30 {
31     return env_ && val_;
32 }
33 
TypeIs(napi_valuetype expType) const34 bool NVal::TypeIs(napi_valuetype expType) const
35 {
36     if (!*this) {
37         return false;
38     }
39 
40     napi_valuetype valueType;
41     napi_typeof(env_, val_, &valueType);
42     if (expType != valueType) {
43         return false;
44     }
45 
46     return true;
47 }
48 
TypeIsError(bool checkErrno) const49 bool NVal::TypeIsError(bool checkErrno) const
50 {
51     if (!*this) {
52         return false;
53     }
54 
55     bool res = false;
56     napi_is_error(env_, val_, &res);
57 
58     return res;
59 }
60 
ToUTF8StringPath() const61 std::tuple<bool, std::unique_ptr<char[]>, size_t> NVal::ToUTF8StringPath() const
62 {
63     auto [succ, path, strLen] = ToUTF8String();
64     if (succ == false || std::strlen(path.get()) < strLen) {
65         return { false, nullptr, 0 };
66     }
67     return make_tuple(true, move(path), strLen);
68 }
69 
ToUTF8String() const70 tuple<bool, unique_ptr<char[]>, size_t> NVal::ToUTF8String() const
71 {
72     size_t strLen = 0;
73     napi_status status = napi_get_value_string_utf8(env_, val_, nullptr, -1, &strLen);
74     if (status != napi_ok) {
75         return { false, nullptr, 0 };
76     }
77 
78     size_t bufLen = strLen + 1;
79     unique_ptr<char[]> str = make_unique<char[]>(bufLen);
80     status = napi_get_value_string_utf8(env_, val_, str.get(), bufLen, &strLen);
81     return make_tuple(status == napi_ok, move(str), strLen);
82 }
83 
ToUTF8String(string_view defaultValue) const84 tuple<bool, unique_ptr<char[]>, size_t> NVal::ToUTF8String(string_view defaultValue) const
85 {
86     if (TypeIs(napi_undefined) || TypeIs(napi_function)) {
87         auto str = make_unique<char[]>(defaultValue.size() + 1);
88         copy(defaultValue.begin(), defaultValue.end(), str.get());
89         return make_tuple(true, move(str), defaultValue.size());
90     }
91     return ToUTF8String();
92 }
93 
ToUTF16String() const94 tuple<bool, unique_ptr<char[]>, size_t> NVal::ToUTF16String() const
95 {
96 #ifdef FILE_SUBSYSTEM_DEBUG_LOCAL
97     size_t strLen = 0;
98     napi_status status = napi_get_value_string_utf16(env_, val_, nullptr, -1, &strLen);
99     if (status != napi_ok) {
100         return { false, nullptr, 0 };
101     }
102 
103     auto str = make_unique<char16_t[]>(++strLen);
104     status = napi_get_value_string_utf16(env_, val_, str.get(), strLen, nullptr);
105     if (status != napi_ok) {
106         return { false, nullptr, 0 };
107     }
108 
109     strLen = reinterpret_cast<char *>(str.get() + strLen) - reinterpret_cast<char *>(str.get());
110     auto strRet = unique_ptr<char[]>(reinterpret_cast<char *>(str.release()));
111     return { true, move(strRet), strLen };
112 #else
113     // Note that quickjs doesn't support utf16
114     return ToUTF8String();
115 #endif
116 }
117 
ToPointer() const118 tuple<bool, void *> NVal::ToPointer() const
119 {
120     void *res = nullptr;
121     napi_status status = napi_get_value_external(env_, val_, &res);
122     return make_tuple(status == napi_ok, res);
123 }
124 
ToBool() const125 tuple<bool, bool> NVal::ToBool() const
126 {
127     bool flag = false;
128     napi_status status = napi_get_value_bool(env_, val_, &flag);
129     return make_tuple(status == napi_ok, flag);
130 }
131 
ToBool(bool defaultValue) const132 tuple<bool, bool> NVal::ToBool(bool defaultValue) const
133 {
134     if (TypeIs(napi_undefined) || TypeIs(napi_function)) {
135         return make_tuple(true, defaultValue);
136     }
137     return ToBool();
138 }
139 
ToInt32() const140 tuple<bool, int32_t> NVal::ToInt32() const
141 {
142     int32_t res = 0;
143     napi_status status = napi_get_value_int32(env_, val_, &res);
144     return make_tuple(status == napi_ok, res);
145 }
146 
ToInt32(int32_t defaultValue) const147 tuple<bool, int32_t> NVal::ToInt32(int32_t defaultValue) const
148 {
149     if (TypeIs(napi_undefined) || TypeIs(napi_function)) {
150         return make_tuple(true, defaultValue);
151     }
152     return ToInt32();
153 }
154 
ToInt64() const155 tuple<bool, int64_t> NVal::ToInt64() const
156 {
157     int64_t res = 0;
158     napi_status status = napi_get_value_int64(env_, val_, &res);
159     return make_tuple(status == napi_ok, res);
160 }
161 
ToInt64(int64_t defaultValue) const162 tuple<bool, int64_t> NVal::ToInt64(int64_t defaultValue) const
163 {
164     if (TypeIs(napi_undefined) || TypeIs(napi_function)) {
165         return make_tuple(true, defaultValue);
166     }
167     return ToInt64();
168 }
169 
ToDouble() const170 tuple<bool, double> NVal::ToDouble() const
171 {
172     double res = 0;
173     napi_status status = napi_get_value_double(env_, val_, &res);
174     return make_tuple(status == napi_ok, res);
175 }
176 
ToUint64() const177 tuple<bool, uint64_t, bool> NVal::ToUint64() const
178 {
179     uint64_t res = 0;
180     bool lossless = false;
181     napi_status status = napi_get_value_bigint_uint64(env_, val_, &res, &lossless);
182     return make_tuple(status == napi_ok, res, lossless);
183 }
184 
ToStringArray()185 tuple<bool, vector<string>, uint32_t> NVal::ToStringArray()
186 {
187     napi_status status;
188     uint32_t size;
189     status = napi_get_array_length(env_, val_, &size);
190     vector<string> stringArray;
191     napi_value result;
192     for (uint32_t i = 0; i < size; i++) {
193         status = napi_get_element(env_, val_, i, &result);
194         auto [succ, str, ignore] = NVal(env_, result).ToUTF8String();
195         stringArray.push_back(string(str.get()));
196     }
197     return make_tuple(status == napi_ok, stringArray, size);
198 }
199 
ToArraybuffer() const200 tuple<bool, void *, size_t> NVal::ToArraybuffer() const
201 {
202     void *buf = nullptr;
203     size_t bufLen = 0;
204     bool status = napi_get_arraybuffer_info(env_, val_, &buf, &bufLen);
205     return make_tuple(status == napi_ok, buf, bufLen);
206 }
207 
ToTypedArray() const208 tuple<bool, void *, size_t> NVal::ToTypedArray() const
209 {
210     napi_typedarray_type type;
211     napi_value in_array_buffer = nullptr;
212     size_t byte_offset;
213     size_t length;
214     void *data = nullptr;
215     napi_status status =
216         napi_get_typedarray_info(env_, val_, &type, &length, (void **)&data, &in_array_buffer, &byte_offset);
217     return make_tuple(status == napi_ok, data, length);
218 }
219 
HasProp(string propName) const220 bool NVal::HasProp(string propName) const
221 {
222     bool res = false;
223 
224     if (!env_ || !val_ || !TypeIs(napi_object))
225         return false;
226     napi_status status = napi_has_named_property(env_, val_, propName.c_str(), &res);
227     return (status == napi_ok) && res;
228 }
229 
GetProp(string propName) const230 NVal NVal::GetProp(string propName) const
231 {
232     if (!HasProp(propName)) {
233         return { env_, nullptr };
234     }
235 
236     napi_value prop = nullptr;
237     napi_status status = napi_get_named_property(env_, val_, propName.c_str(), &prop);
238     if (status != napi_ok) {
239         return { env_, nullptr };
240     }
241 
242     return NVal(env_, prop);
243 }
244 
AddProp(vector<napi_property_descriptor> && propVec) const245 bool NVal::AddProp(vector<napi_property_descriptor> &&propVec) const
246 {
247     if (!TypeIs(napi_valuetype::napi_object)) {
248         HILOGE("INNER BUG. Prop should only be added to objects");
249         return false;
250     }
251 
252     napi_status status = napi_define_properties(env_, val_, propVec.size(), propVec.data());
253     if (status != napi_ok) {
254         HILOGE("INNER BUG. Cannot define properties because of %{public}d", status);
255         return false;
256     }
257 
258     return true;
259 }
260 
AddProp(string propName,napi_value val) const261 bool NVal::AddProp(string propName, napi_value val) const
262 {
263     if (!TypeIs(napi_valuetype::napi_object) || HasProp(propName)) {
264         HILOGE("INNER BUG. Prop should only be added to objects");
265         return false;
266     }
267 
268     napi_status status = napi_set_named_property(env_, val_, propName.c_str(), val);
269     if (status != napi_ok) {
270         HILOGE("INNER BUG. Cannot set named property because of %{public}d", status);
271         return false;
272     }
273 
274     return true;
275 }
276 
CreateUndefined(napi_env env)277 NVal NVal::CreateUndefined(napi_env env)
278 {
279     napi_value res = nullptr;
280     napi_get_undefined(env, &res);
281     return { env, res };
282 }
283 
CreateBigInt64(napi_env env,int64_t val)284 NVal NVal::CreateBigInt64(napi_env env, int64_t val)
285 {
286     napi_value res = nullptr;
287     napi_create_bigint_int64(env, val, &res);
288     return { env, res };
289 }
290 
CreateInt64(napi_env env,int64_t val)291 NVal NVal::CreateInt64(napi_env env, int64_t val)
292 {
293     napi_value res = nullptr;
294     napi_create_int64(env, val, &res);
295     return { env, res };
296 }
297 
CreateInt32(napi_env env,int32_t val)298 NVal NVal::CreateInt32(napi_env env, int32_t val)
299 {
300     napi_value res = nullptr;
301     napi_create_int32(env, val, &res);
302     return { env, res };
303 }
304 
CreateObject(napi_env env)305 NVal NVal::CreateObject(napi_env env)
306 {
307     napi_value res = nullptr;
308     napi_create_object(env, &res);
309     return { env, res };
310 }
311 
CreateBool(napi_env env,bool val)312 NVal NVal::CreateBool(napi_env env, bool val)
313 {
314     napi_value res = nullptr;
315     napi_get_boolean(env, val, &res);
316     return { env, res };
317 }
318 
CreateUTF8String(napi_env env,std::string str)319 NVal NVal::CreateUTF8String(napi_env env, std::string str)
320 {
321     napi_value res = nullptr;
322     napi_create_string_utf8(env, str.c_str(), str.length(), &res);
323     return { env, res };
324 }
325 
CreateUTF8String(napi_env env,const char * str,ssize_t len)326 NVal NVal::CreateUTF8String(napi_env env, const char* str, ssize_t len)
327 {
328     napi_value res = nullptr;
329     napi_create_string_utf8(env, str, len, &res);
330     return { env, res };
331 }
332 
CreateUint8Array(napi_env env,void * buf,size_t bufLen)333 NVal NVal::CreateUint8Array(napi_env env, void *buf, size_t bufLen)
334 {
335     napi_value output_buffer = nullptr;
336     napi_create_external_arraybuffer(
337         env,
338         buf,
339         bufLen,
340         [](napi_env env, void *finalize_data, void *finalize_hint) { free(finalize_data); },
341         NULL,
342         &output_buffer);
343     napi_value output_array = nullptr;
344     napi_create_typedarray(env, napi_uint8_array, bufLen, output_buffer, 0, &output_array);
345     return { env, output_array };
346 }
347 
CreateArrayString(napi_env env,vector<string> strs)348 NVal NVal::CreateArrayString(napi_env env, vector<string> strs)
349 {
350     napi_value res = nullptr;
351     napi_create_array(env, &res);
352     for (size_t i = 0; i < strs.size(); i++) {
353         napi_value filename;
354         napi_create_string_utf8(env, strs[i].c_str(), strs[i].length(), &filename);
355         napi_set_element(env, res, i, filename);
356     }
357     return {env, res};
358 }
359 
CreateArrayBuffer(napi_env env,size_t len)360 tuple<NVal, void *> NVal::CreateArrayBuffer(napi_env env, size_t len)
361 {
362     napi_value val;
363     void *buf = nullptr;
364     napi_create_arraybuffer(env, len, &buf, &val);
365     return { { env, val }, { buf } };
366 }
367 
DeclareNapiProperty(const char * name,napi_value val)368 napi_property_descriptor NVal::DeclareNapiProperty(const char *name, napi_value val)
369 {
370     return { (name), nullptr, nullptr, nullptr, nullptr, val, napi_default, nullptr };
371 }
372 
DeclareNapiStaticProperty(const char * name,napi_value val)373 napi_property_descriptor NVal::DeclareNapiStaticProperty(const char *name, napi_value val)
374 {
375     return { (name), nullptr, nullptr, nullptr, nullptr, val, napi_static, nullptr };
376 }
377 
DeclareNapiFunction(const char * name,napi_callback func)378 napi_property_descriptor NVal::DeclareNapiFunction(const char *name, napi_callback func)
379 {
380     return { (name), nullptr, (func), nullptr, nullptr, nullptr, napi_default, nullptr };
381 }
382 
DeclareNapiStaticFunction(const char * name,napi_callback func)383 napi_property_descriptor NVal::DeclareNapiStaticFunction(const char *name, napi_callback func)
384 {
385     return { (name), nullptr, (func), nullptr, nullptr, nullptr, napi_static, nullptr };
386 }
387 
DeclareNapiGetter(const char * name,napi_callback getter)388 napi_property_descriptor NVal::DeclareNapiGetter(const char *name, napi_callback getter)
389 {
390     return { (name), nullptr, nullptr, (getter), nullptr, nullptr, napi_default, nullptr };
391 }
392 
DeclareNapiSetter(const char * name,napi_callback setter)393 napi_property_descriptor NVal::DeclareNapiSetter(const char *name, napi_callback setter)
394 {
395     return { (name), nullptr, nullptr, nullptr, (setter), nullptr, napi_default, nullptr };
396 }
397 
DeclareNapiGetterSetter(const char * name,napi_callback getter,napi_callback setter)398 napi_property_descriptor NVal::DeclareNapiGetterSetter(const char *name, napi_callback getter, napi_callback setter)
399 {
400     return { (name), nullptr, nullptr, (getter), (setter), nullptr, napi_default, nullptr };
401 }
402 } // namespace DistributedFS
403 } // namespace OHOS