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 "napi/n_val.h"
17 
18 #include <limits>
19 #include <sstream>
20 #include <string>
21 #include "securec.h"
22 #include "util/log.h"
23 #include "napi/n_class.h"
24 
25 namespace OHOS {
26 namespace Rosen {
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 
42     napi_valuetype valueType;
43     napi_typeof(env_, val_, &valueType);
44 
45     if (expType != valueType) {
46         return false;
47     }
48     return true;
49 }
50 
IsNull() const51 bool NVal::IsNull() const
52 {
53     if (val_ == nullptr) {
54         return true;
55     }
56     napi_valuetype valueType;
57     napi_typeof(env_, val_, &valueType);
58     if (valueType == napi_null) {
59         return true;
60     }
61     if (valueType == napi_undefined) {
62         return true;
63     }
64     return false;
65 }
66 
IsUndefined() const67 bool NVal::IsUndefined() const
68 {
69     if (val_ == nullptr) {
70         return false;
71     }
72     napi_valuetype valueType;
73     napi_typeof(env_, val_, &valueType);
74     if (valueType == napi_undefined) {
75         return true;
76     }
77     return false;
78 }
79 
IsBufferArray() const80 bool NVal::IsBufferArray() const
81 {
82     if (val_ == nullptr) {
83         return false;
84     }
85     bool type = false;
86     napi_is_dataview(env_, val_, &type);
87     if (type) {
88         return true;
89     }
90     napi_is_arraybuffer(env_, val_, &type);
91     if (type) {
92         return true;
93     }
94     napi_is_typedarray(env_, val_, &type);
95     if (type) {
96         return true;
97     }
98     return false;
99 }
100 
IsArray() const101 tuple<bool, bool> NVal::IsArray() const
102 {
103     bool res = false;
104     napi_status status = napi_is_array(env_, val_, &res);
105     return make_tuple(status == napi_ok, res);
106 }
107 
ToUTF8String() const108 tuple<bool, unique_ptr<char[]>, size_t> NVal::ToUTF8String() const
109 {
110     napi_valuetype valueType;
111     napi_typeof(env_, val_, &valueType);
112     if (valueType == napi_null) {
113         unique_ptr<char[]> str = make_unique<char[]>(1);
114         str[0] = '\0';
115         return {true, move(str), 0};
116     } else if (valueType != napi_string) {
117         return {false, nullptr, 0};
118     }
119     size_t strLen = 0;
120     napi_status status = napi_get_value_string_utf8(env_, val_, nullptr, -1, &strLen);
121     if (status != napi_ok) {
122         return {false, nullptr, 0};
123     }
124 
125     size_t bufLen = strLen + 1;
126     unique_ptr<char[]> str = make_unique<char[]>(bufLen);
127     status = napi_get_value_string_utf8(env_, val_, str.get(), bufLen, &strLen);
128     return make_tuple(status == napi_ok, move(str), strLen);
129 }
130 
ToUTF16String() const131 tuple<bool, unique_ptr<char[]>, size_t> NVal::ToUTF16String() const
132 {
133 #ifdef FILE_SUBSYSTEM_DEV_ON_PC
134     size_t strLen = 0;
135     napi_status status = napi_get_value_string_utf16(env_, val_, nullptr, -1, &strLen);
136     if (status != napi_ok) {
137         return { false, nullptr, 0 };
138     }
139 
140     auto str = make_unique<char16_t[]>(++strLen);
141     status = napi_get_value_string_utf16(env_, val_, str.get(), strLen, nullptr);
142     if (status != napi_ok) {
143         return { false, nullptr, 0 };
144     }
145 
146     strLen = reinterpret_cast<char *>(str.get() + strLen) - reinterpret_cast<char *>(str.get());
147     auto strRet = unique_ptr<char[]>(reinterpret_cast<char *>(str.release()));
148     return { true, move(strRet), strLen };
149 #else
150     // Note that quickjs doesn't support utf16
151     return ToUTF8String();
152 #endif
153 }
154 
ToPointer() const155 tuple<bool, void *> NVal::ToPointer() const
156 {
157     void *res = nullptr;
158     napi_status status = napi_get_value_external(env_, val_, &res);
159     return make_tuple(status == napi_ok, res);
160 }
161 
IsTypeArray() const162 tuple<bool, bool> NVal::IsTypeArray() const
163 {
164     bool res = false;
165     napi_status status = napi_is_typedarray(env_, val_, &res);
166     return make_tuple(status == napi_ok, res);
167 }
168 
IsDataView() const169 bool NVal::IsDataView() const
170 {
171     bool res = false;
172     napi_status status = napi_is_dataview(env_, val_, &res);
173     return ((status == napi_ok) && res);
174 }
175 
ToBool() const176 tuple<bool, bool> NVal::ToBool() const
177 {
178     bool flag = false;
179     if (IsNull()) {
180         return make_tuple(true, flag);
181     }
182     napi_status status = napi_get_value_bool(env_, val_, &flag);
183     return make_tuple(status == napi_ok, flag);
184 }
185 
ToDouble() const186 tuple<bool, double> NVal::ToDouble() const
187 {
188     double res = 0.0;
189     napi_status status = napi_get_value_double(env_, val_, &res);
190     return make_tuple(status == napi_ok, res);
191 }
192 
ToFloat() const193 tuple<bool, GLfloat> NVal::ToFloat() const
194 {
195     if (IsUndefined()) {
196         float f = 0;
197         memset_s(&f, sizeof(f), 0xff, sizeof(f));
198         return make_tuple(true, f);
199     }
200     if (IsNull()) {
201         return make_tuple(true, 0);
202     }
203     double res = 0.0;
204     napi_status status = napi_get_value_double(env_, val_, &res);
205     return make_tuple(status == napi_ok, static_cast<GLfloat>(res));
206 }
207 
ToInt32() const208 tuple<bool, int32_t> NVal::ToInt32() const
209 {
210     int32_t res = 0;
211     if (IsNull()) {
212         return make_tuple(true, res);
213     }
214     napi_status status = napi_get_value_int32(env_, val_, &res);
215     return make_tuple(status == napi_ok, res);
216 }
217 
ToUint32() const218 tuple<bool, uint32_t> NVal::ToUint32() const
219 {
220     uint32_t res = 0;
221     if (IsNull()) {
222         return make_tuple(true, res);
223     }
224     napi_status status = napi_get_value_uint32(env_, val_, &res);
225     return make_tuple(status == napi_ok, res);
226 }
227 
ToInt64() const228 tuple<bool, int64_t> NVal::ToInt64() const
229 {
230     int64_t res = 0;
231     if (IsNull()) {
232         return make_tuple(true, res);
233     }
234     napi_status status = napi_get_value_int64(env_, val_, &res);
235     return make_tuple(status == napi_ok, res);
236 }
237 
ToGLsizei() const238 tuple<bool, GLsizei> NVal::ToGLsizei() const
239 {
240     int64_t res = 0;
241     if (IsNull()) {
242         return make_tuple(true, res);
243     }
244     napi_status status = napi_get_value_int64(env_, val_, &res);
245     return make_tuple(status == napi_ok, static_cast<GLsizei>(res));
246 }
247 
ToGLenum() const248 tuple<bool, GLenum> NVal::ToGLenum() const
249 {
250     int64_t res = 0;
251     napi_valuetype valueType;
252     napi_typeof(env_, val_, &valueType);
253     if (valueType == napi_null) {
254         return make_tuple(true, static_cast<GLenum>(res));
255     }
256     napi_status status = napi_get_value_int64(env_, val_, &res);
257     return make_tuple(status == napi_ok, static_cast<GLenum>(res));
258 }
259 
ToArraybuffer() const260 tuple<bool, void *, size_t> NVal::ToArraybuffer() const
261 {
262     void *buf = nullptr;
263     size_t bufLen = 0;
264     bool status = napi_get_arraybuffer_info(env_, val_, &buf, &bufLen);
265     return make_tuple(status == napi_ok, buf, bufLen);
266 }
267 
ToTypedArray() const268 tuple<bool, napi_typedarray_type, void *, size_t> NVal::ToTypedArray() const
269 {
270     napi_typedarray_type type;
271     napi_value in_array_buffer = nullptr;
272     size_t byte_offset;
273     size_t length;
274     void *data = nullptr;
275     napi_status status = napi_get_typedarray_info(env_, val_, &type, &length, (void **) &data, &in_array_buffer,
276         &byte_offset);
277     return make_tuple(status == napi_ok, type, data, length);
278 }
279 
ToDataview() const280 tuple<bool, void *, size_t> NVal::ToDataview() const
281 {
282     size_t bufLen = 0;
283     void *buf = nullptr;
284     napi_value arraybuffer = nullptr;
285     size_t byteoff = 0;
286     bool status = napi_get_dataview_info(env_, val_, &bufLen, &buf, &arraybuffer, &byteoff);
287     return make_tuple(status == napi_ok, buf, bufLen);
288 }
289 
ToTypedArrayInfo() const290 tuple<bool, void *, size_t, size_t, napi_typedarray_type> NVal::ToTypedArrayInfo() const
291 {
292     napi_typedarray_type type;
293     napi_value in_array_buffer = nullptr;
294     size_t byte_offset;
295     size_t length;
296     void *data = nullptr;
297     napi_status status =
298         napi_get_typedarray_info(env_, val_, &type, &length, (void **)&data, &in_array_buffer, &byte_offset);
299     return make_tuple(status == napi_ok, data, length, byte_offset, type);
300 }
301 
HasProp(string propName) const302 bool NVal::HasProp(string propName) const
303 {
304     bool res = false;
305 
306     if (!env_ || !val_ || !TypeIs(napi_object)) {
307         return false;
308     }
309 
310     napi_status status = napi_has_named_property(env_, val_, propName.c_str(), &res);
311     return (status == napi_ok) && res;
312 }
313 
GetProp(string propName) const314 NVal NVal::GetProp(string propName) const
315 {
316     if (!HasProp(propName)) {
317         return {env_, nullptr};
318     }
319     napi_value prop = nullptr;
320     napi_status status = napi_get_named_property(env_, val_, propName.c_str(), &prop);
321     if (status != napi_ok) {
322         return {env_, nullptr};
323     }
324     return NVal(env_, prop);
325 }
326 
AddProp(vector<napi_property_descriptor> && propVec) const327 bool NVal::AddProp(vector<napi_property_descriptor> &&propVec) const
328 {
329     if (!TypeIs(napi_valuetype::napi_object)) {
330         return false;
331     }
332     napi_status status = napi_define_properties(env_, val_, propVec.size(), propVec.data());
333     if (status != napi_ok) {
334         return false;
335     }
336     return true;
337 }
338 
AddProp(string propName,napi_value val) const339 bool NVal::AddProp(string propName, napi_value val) const
340 {
341     if (!TypeIs(napi_valuetype::napi_object) || HasProp(propName)) {
342         return false;
343     }
344 
345     napi_status status = napi_set_named_property(env_, val_, propName.c_str(), val);
346     if (status != napi_ok) {
347         return false;
348     }
349     return true;
350 }
351 
CreateUndefined(napi_env env)352 NVal NVal::CreateUndefined(napi_env env)
353 {
354     napi_value res = nullptr;
355     napi_get_undefined(env, &res);
356     return {env, res};
357 }
358 
CreateNull(napi_env env)359 NVal NVal::CreateNull(napi_env env)
360 {
361     napi_value res = nullptr;
362     napi_get_null(env, &res);
363     return {env, res};
364 }
365 
CreateInt64(napi_env env,int64_t val)366 NVal NVal::CreateInt64(napi_env env, int64_t val)
367 {
368     napi_value res = nullptr;
369     napi_create_int64(env, val, &res);
370     return {env, res};
371 }
372 
CreateObject(napi_env env)373 NVal NVal::CreateObject(napi_env env)
374 {
375     napi_value res = nullptr;
376     napi_create_object(env, &res);
377     return {env, res};
378 }
379 
CreateBool(napi_env env,bool val)380 NVal NVal::CreateBool(napi_env env, bool val)
381 {
382     napi_value res = nullptr;
383     napi_get_boolean(env, val, &res);
384     return {env, res};
385 }
386 
CreateUTF8String(napi_env env,std::string str)387 NVal NVal::CreateUTF8String(napi_env env, std::string str)
388 {
389     napi_value res = nullptr;
390     napi_create_string_utf8(env, str.c_str(), str.length(), &res);
391     return {env, res};
392 }
393 
CreateUint8Array(napi_env env,void * buf,size_t bufLen)394 NVal NVal::CreateUint8Array(napi_env env, void *buf, size_t bufLen)
395 {
396     napi_value output_buffer = nullptr;
397     napi_create_external_arraybuffer(env, buf, bufLen,
398         [](napi_env env, void *finalize_data, void *finalize_hint) { free(finalize_data); },
399         NULL, &output_buffer);
400     napi_value output_array = nullptr;
401     napi_create_typedarray(env, napi_uint8_array, bufLen, output_buffer, 0, &output_array);
402     return {env, output_array};
403 }
404 
CreateDouble(napi_env env,double val)405 NVal NVal::CreateDouble(napi_env env, double val)
406 {
407     napi_value res = nullptr;
408     napi_create_double(env, val, &res);
409     return {env, res};
410 }
411 
DeclareNapiProperty(const char * name,napi_value val)412 napi_property_descriptor NVal::DeclareNapiProperty(const char *name, napi_value val)
413 {
414     return {(name), nullptr, nullptr, nullptr, nullptr, val, napi_default, nullptr};
415 }
416 
DeclareNapiStaticProperty(const char * name,napi_value val)417 napi_property_descriptor NVal::DeclareNapiStaticProperty(const char *name, napi_value val)
418 {
419     return {(name), nullptr, nullptr, nullptr, nullptr, val, napi_static, nullptr};
420 }
421 
DeclareNapiFunction(const char * name,napi_callback func)422 napi_property_descriptor NVal::DeclareNapiFunction(const char *name, napi_callback func)
423 {
424     return {(name), nullptr, (func), nullptr, nullptr, nullptr, napi_default, nullptr};
425 }
426 
DeclareNapiStaticFunction(const char * name,napi_callback func)427 napi_property_descriptor NVal::DeclareNapiStaticFunction(const char *name, napi_callback func)
428 {
429     return {(name), nullptr, (func), nullptr, nullptr, nullptr, napi_static, nullptr};
430 }
431 
DeclareNapiGetter(const char * name,napi_callback getter)432 napi_property_descriptor NVal::DeclareNapiGetter(const char *name, napi_callback getter)
433 {
434     return {(name), nullptr, nullptr, (getter), nullptr, nullptr, napi_default, nullptr};
435 }
436 
DeclareNapiSetter(const char * name,napi_callback setter)437 napi_property_descriptor NVal::DeclareNapiSetter(const char *name, napi_callback setter)
438 {
439     return {(name), nullptr, nullptr, nullptr, (setter), nullptr, napi_default, nullptr};
440 }
441 
DeclareNapiGetterSetter(const char * name,napi_callback getter,napi_callback setter)442 napi_property_descriptor NVal::DeclareNapiGetterSetter(const char *name, napi_callback getter, napi_callback setter)
443 {
444     return {(name), nullptr, nullptr, (getter), (setter), nullptr, napi_default, nullptr};
445 }
446 } // namespace Rosen
447 } // namespace OHOS
448