• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "napi_utils.h"
17 
18 #include <cstdlib>
19 #include <cstring>
20 #include <initializer_list>
21 #include <memory>
22 #include <algorithm>
23 #include <new>
24 #include <string>
25 #include <vector>
26 
27 #include "securec.h"
28 #include "napi/native_api.h"
29 #include "napi/native_common.h"
30 #include "node_api.h"
31 #include "base_context.h"
32 
33 namespace OHOS::NetStack::NapiUtils {
34 static constexpr const char *GLOBAL_JSON = "JSON";
35 
36 static constexpr const char *GLOBAL_JSON_STRINGIFY = "stringify";
37 
38 static constexpr const char *GLOBAL_JSON_PARSE = "parse";
39 
40 static constexpr const char *CODE = "code";
41 
42 static constexpr const char *MSG = "message";
43 
GetValueType(napi_env env,napi_value value)44 napi_valuetype GetValueType(napi_env env, napi_value value)
45 {
46     if (value == nullptr) {
47         return napi_undefined;
48     }
49 
50     napi_valuetype valueType = napi_undefined;
51     NAPI_CALL_BASE(env, napi_typeof(env, value, &valueType), napi_undefined);
52     return valueType;
53 }
54 
55 /* named property */
HasNamedProperty(napi_env env,napi_value object,const std::string & propertyName)56 bool HasNamedProperty(napi_env env, napi_value object, const std::string &propertyName)
57 {
58     if (GetValueType(env, object) != napi_object) {
59         return false;
60     }
61 
62     bool hasProperty = false;
63     NAPI_CALL_BASE(env, napi_has_named_property(env, object, propertyName.c_str(), &hasProperty), false);
64     return hasProperty;
65 }
66 
GetNamedProperty(napi_env env,napi_value object,const std::string & propertyName)67 napi_value GetNamedProperty(napi_env env, napi_value object, const std::string &propertyName)
68 {
69     if (GetValueType(env, object) != napi_object) {
70         return GetUndefined(env);
71     }
72 
73     napi_value value = nullptr;
74     NAPI_CALL(env, napi_get_named_property(env, object, propertyName.c_str(), &value));
75     return value;
76 }
77 
SetNamedProperty(napi_env env,napi_value object,const std::string & name,napi_value value)78 void SetNamedProperty(napi_env env, napi_value object, const std::string &name, napi_value value)
79 {
80     if (GetValueType(env, object) != napi_object) {
81         return;
82     }
83 
84     napi_set_named_property(env, object, name.c_str(), value);
85 }
86 
GetPropertyNames(napi_env env,napi_value object)87 std::vector<std::string> GetPropertyNames(napi_env env, napi_value object)
88 {
89     if (GetValueType(env, object) != napi_object) {
90         return {};
91     }
92 
93     std::vector<std::string> ret;
94     napi_value names = nullptr;
95     NAPI_CALL_BASE(env, napi_get_property_names(env, object, &names), ret);
96     uint32_t length = 0;
97     NAPI_CALL_BASE(env, napi_get_array_length(env, names, &length), ret);
98     for (uint32_t index = 0; index < length; ++index) {
99         napi_value name = nullptr;
100         if (napi_get_element(env, names, index, &name) != napi_ok) {
101             continue;
102         }
103         if (GetValueType(env, name) != napi_string) {
104             continue;
105         }
106         ret.emplace_back(GetStringFromValueUtf8(env, name));
107     }
108     return ret;
109 }
110 
111 /* UINT32 */
CreateUint32(napi_env env,uint32_t code)112 napi_value CreateUint32(napi_env env, uint32_t code)
113 {
114     napi_value value = nullptr;
115     if (napi_create_uint32(env, code, &value) != napi_ok) {
116         return nullptr;
117     }
118     return value;
119 }
120 
121 /* UINT64 */
CreateUint64(napi_env env,uint64_t code)122 napi_value CreateUint64(napi_env env, uint64_t code)
123 {
124     napi_value value = nullptr;
125     if (napi_create_bigint_uint64(env, code, &value) != napi_ok) {
126         return nullptr;
127     }
128     return value;
129 }
130 
GetUint32FromValue(napi_env env,napi_value value)131 uint32_t GetUint32FromValue(napi_env env, napi_value value)
132 {
133     if (GetValueType(env, value) != napi_number) {
134         return 0;
135     }
136 
137     uint32_t ret = 0;
138     NAPI_CALL_BASE(env, napi_get_value_uint32(env, value, &ret), 0);
139     return ret;
140 }
141 
GetUint32Property(napi_env env,napi_value object,const std::string & propertyName)142 uint32_t GetUint32Property(napi_env env, napi_value object, const std::string &propertyName)
143 {
144     if (!HasNamedProperty(env, object, propertyName)) {
145         return 0;
146     }
147     napi_value value = GetNamedProperty(env, object, propertyName);
148     return GetUint32FromValue(env, value);
149 }
150 
SetUint32Property(napi_env env,napi_value object,const std::string & name,uint32_t value)151 void SetUint32Property(napi_env env, napi_value object, const std::string &name, uint32_t value)
152 {
153     napi_value jsValue = CreateUint32(env, value);
154     if (GetValueType(env, jsValue) != napi_number) {
155         return;
156     }
157 
158     napi_set_named_property(env, object, name.c_str(), jsValue);
159 }
160 
SetUint64Property(napi_env env,napi_value object,const std::string & name,uint64_t value)161 void SetUint64Property(napi_env env, napi_value object, const std::string &name, uint64_t value)
162 {
163     napi_value jsValue = CreateUint64(env, value);
164     if (GetValueType(env, jsValue) != napi_bigint) {
165         return;
166     }
167 
168     napi_set_named_property(env, object, name.c_str(), jsValue);
169 }
170 
171 /* INT32 */
CreateInt32(napi_env env,int32_t code)172 napi_value CreateInt32(napi_env env, int32_t code)
173 {
174     napi_value value = nullptr;
175     if (napi_create_int32(env, code, &value) != napi_ok) {
176         return nullptr;
177     }
178     return value;
179 }
180 
GetInt32FromValue(napi_env env,napi_value value)181 int32_t GetInt32FromValue(napi_env env, napi_value value)
182 {
183     if (GetValueType(env, value) != napi_number) {
184         return 0;
185     }
186 
187     int32_t ret = 0;
188     NAPI_CALL_BASE(env, napi_get_value_int32(env, value, &ret), 0);
189     return ret;
190 }
191 
GetInt32Property(napi_env env,napi_value object,const std::string & propertyName)192 int32_t GetInt32Property(napi_env env, napi_value object, const std::string &propertyName)
193 {
194     if (!HasNamedProperty(env, object, propertyName)) {
195         return 0;
196     }
197     napi_value value = GetNamedProperty(env, object, propertyName);
198     return GetInt32FromValue(env, value);
199 }
200 
SetInt32Property(napi_env env,napi_value object,const std::string & name,int32_t value)201 void SetInt32Property(napi_env env, napi_value object, const std::string &name, int32_t value)
202 {
203     napi_value jsValue = CreateInt32(env, value);
204     if (GetValueType(env, jsValue) != napi_number) {
205         return;
206     }
207 
208     napi_set_named_property(env, object, name.c_str(), jsValue);
209 }
210 
211 /* String UTF8 */
CreateStringUtf8(napi_env env,const std::string & str)212 napi_value CreateStringUtf8(napi_env env, const std::string &str)
213 {
214     napi_value value = nullptr;
215     if (napi_create_string_utf8(env, str.c_str(), strlen(str.c_str()), &value) != napi_ok) {
216         return nullptr;
217     }
218     return value;
219 }
220 
GetStringFromValueUtf8(napi_env env,napi_value value)221 std::string GetStringFromValueUtf8(napi_env env, napi_value value)
222 {
223     if (GetValueType(env, value) != napi_string) {
224         return {};
225     }
226 
227     std::string result;
228     size_t stringLength = 0;
229     NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, value, nullptr, 0, &stringLength), result);
230     if (stringLength == 0) {
231         return result;
232     }
233 
234     auto deleter = [](char *s) { free(reinterpret_cast<void *>(s)); };
235     std::unique_ptr<char, decltype(deleter)> str(static_cast<char *>(malloc(stringLength + 1)), deleter);
236     if (memset_s(str.get(), stringLength + 1, 0, stringLength + 1) != EOK) {
237         return result;
238     }
239     size_t length = 0;
240     NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, value, str.get(), stringLength + 1, &length), result);
241     if (length > 0) {
242         result.append(str.get(), length);
243     }
244     return result;
245 }
246 
GetStringPropertyUtf8(napi_env env,napi_value object,const std::string & propertyName)247 std::string GetStringPropertyUtf8(napi_env env, napi_value object, const std::string &propertyName)
248 {
249     if (!HasNamedProperty(env, object, propertyName)) {
250         return "";
251     }
252     napi_value value = GetNamedProperty(env, object, propertyName);
253     return GetStringFromValueUtf8(env, value);
254 }
255 
SetStringPropertyUtf8(napi_env env,napi_value object,const std::string & name,const std::string & value)256 void SetStringPropertyUtf8(napi_env env, napi_value object, const std::string &name, const std::string &value)
257 {
258     napi_value jsValue = CreateStringUtf8(env, value);
259     if (GetValueType(env, jsValue) != napi_string) {
260         return;
261     }
262     napi_set_named_property(env, object, name.c_str(), jsValue);
263 }
264 
265 /* array buffer */
ValueIsArrayBuffer(napi_env env,napi_value value)266 bool ValueIsArrayBuffer(napi_env env, napi_value value)
267 {
268     if (value == nullptr) {
269         return false;
270     }
271     bool isArrayBuffer = false;
272     NAPI_CALL_BASE(env, napi_is_arraybuffer(env, value, &isArrayBuffer), false);
273     return isArrayBuffer;
274 }
275 
GetInfoFromArrayBufferValue(napi_env env,napi_value value,size_t * length)276 void *GetInfoFromArrayBufferValue(napi_env env, napi_value value, size_t *length)
277 {
278     if (length == nullptr) {
279         return nullptr;
280     }
281 
282     void *data = nullptr;
283     NAPI_CALL(env, napi_get_arraybuffer_info(env, value, &data, length));
284     return data;
285 }
286 
CreateArrayBuffer(napi_env env,size_t length,void ** data)287 napi_value CreateArrayBuffer(napi_env env, size_t length, void **data)
288 {
289     if (length == 0) {
290         return nullptr;
291     }
292     napi_value result = nullptr;
293     NAPI_CALL(env, napi_create_arraybuffer(env, length, data, &result));
294     return result;
295 }
296 
297 /* object */
CreateObject(napi_env env)298 napi_value CreateObject(napi_env env)
299 {
300     napi_value object = nullptr;
301     NAPI_CALL(env, napi_create_object(env, &object));
302     return object;
303 }
304 
305 /* undefined */
GetUndefined(napi_env env)306 napi_value GetUndefined(napi_env env)
307 {
308     napi_value undefined = nullptr;
309     NAPI_CALL(env, napi_get_undefined(env, &undefined));
310     return undefined;
311 }
312 
313 /* function */
CallFunction(napi_env env,napi_value recv,napi_value func,size_t argc,const napi_value * argv)314 napi_value CallFunction(napi_env env, napi_value recv, napi_value func, size_t argc, const napi_value *argv)
315 {
316     napi_value res = nullptr;
317     NAPI_CALL(env, napi_call_function(env, recv, func, argc, argv, &res));
318     return res;
319 }
320 
CreateFunction(napi_env env,const std::string & name,napi_callback func,void * arg)321 napi_value CreateFunction(napi_env env, const std::string &name, napi_callback func, void *arg)
322 {
323     napi_value res = nullptr;
324     NAPI_CALL(env, napi_create_function(env, name.c_str(), strlen(name.c_str()), func, arg, &res));
325     return res;
326 }
327 
328 /* reference */
CreateReference(napi_env env,napi_value callback)329 napi_ref CreateReference(napi_env env, napi_value callback)
330 {
331     napi_ref callbackRef = nullptr;
332     NAPI_CALL(env, napi_create_reference(env, callback, 1, &callbackRef));
333     return callbackRef;
334 }
335 
GetReference(napi_env env,napi_ref callbackRef)336 napi_value GetReference(napi_env env, napi_ref callbackRef)
337 {
338     napi_value callback = nullptr;
339     NAPI_CALL(env, napi_get_reference_value(env, callbackRef, &callback));
340     return callback;
341 }
342 
DeleteReference(napi_env env,napi_ref callbackRef)343 void DeleteReference(napi_env env, napi_ref callbackRef)
344 {
345     (void)napi_delete_reference(env, callbackRef);
346 }
347 
348 /* boolean */
GetBooleanProperty(napi_env env,napi_value object,const std::string & propertyName)349 bool GetBooleanProperty(napi_env env, napi_value object, const std::string &propertyName)
350 {
351     if (!HasNamedProperty(env, object, propertyName)) {
352         return false;
353     }
354     napi_value value = GetNamedProperty(env, object, propertyName);
355     bool ret = false;
356     NAPI_CALL_BASE(env, napi_get_value_bool(env, value, &ret), false);
357     return ret;
358 }
359 
SetBooleanProperty(napi_env env,napi_value object,const std::string & name,bool value)360 void SetBooleanProperty(napi_env env, napi_value object, const std::string &name, bool value)
361 {
362     napi_value jsValue = nullptr;
363     NAPI_CALL_RETURN_VOID(env, napi_get_boolean(env, value, &jsValue));
364     if (GetValueType(env, jsValue) != napi_boolean) {
365         return;
366     }
367 
368     napi_set_named_property(env, object, name.c_str(), jsValue);
369 }
370 
GetBoolean(napi_env env,bool value)371 napi_value GetBoolean(napi_env env, bool value)
372 {
373     napi_value jsValue = nullptr;
374     NAPI_CALL(env, napi_get_boolean(env, value, &jsValue));
375     return jsValue;
376 }
377 
GetBooleanFromValue(napi_env env,napi_value value)378 bool GetBooleanFromValue(napi_env env, napi_value value)
379 {
380     if (GetValueType(env, value) != napi_boolean) {
381         return GetUndefined(env);
382     }
383 
384     bool ret = false;
385     NAPI_CALL_BASE(env, napi_get_value_bool(env, value, &ret), false);
386     return ret;
387 }
388 
389 /* define properties */
DefineProperties(napi_env env,napi_value object,const std::initializer_list<napi_property_descriptor> & properties)390 void DefineProperties(napi_env env, napi_value object,
391                       const std::initializer_list<napi_property_descriptor> &properties)
392 {
393     napi_property_descriptor descriptors[properties.size()];
394     std::copy(properties.begin(), properties.end(), descriptors);
395 
396     (void)napi_define_properties(env, object, properties.size(), descriptors);
397 }
398 
399 /* array */
CreateArray(napi_env env,size_t length)400 napi_value CreateArray(napi_env env, size_t length)
401 {
402     if (length == 0) {
403         napi_value res = nullptr;
404         NAPI_CALL(env, napi_create_array(env, &res));
405         return res;
406     }
407     napi_value res = nullptr;
408     NAPI_CALL(env, napi_create_array_with_length(env, length, &res));
409     return res;
410 }
411 
SetArrayElement(napi_env env,napi_value array,uint32_t index,napi_value value)412 void SetArrayElement(napi_env env, napi_value array, uint32_t index, napi_value value)
413 {
414     (void)napi_set_element(env, array, index, value);
415 }
416 
IsArray(napi_env env,napi_value value)417 bool IsArray(napi_env env, napi_value value)
418 {
419     bool result = false;
420     NAPI_CALL_BASE(env, napi_is_array(env, value, &result), false);
421     return result;
422 }
423 
GetArrayLength(napi_env env,napi_value arr)424 uint32_t GetArrayLength(napi_env env, napi_value arr)
425 {
426     uint32_t arrayLength = 0;
427     NAPI_CALL_BASE(env, napi_get_array_length(env, arr, &arrayLength), 0);
428     return arrayLength;
429 }
430 
GetArrayElement(napi_env env,napi_value arr,uint32_t index)431 napi_value GetArrayElement(napi_env env, napi_value arr, uint32_t index)
432 {
433     napi_value elementValue = nullptr;
434     NAPI_CALL(env, napi_get_element(env, arr, index, &elementValue));
435     return elementValue;
436 }
437 
438 /* JSON */
JsonStringify(napi_env env,napi_value object)439 napi_value JsonStringify(napi_env env, napi_value object)
440 {
441     napi_value undefined = GetUndefined(env);
442 
443     if (GetValueType(env, object) != napi_object) {
444         return undefined;
445     }
446 
447     napi_value global = nullptr;
448     NAPI_CALL_BASE(env, napi_get_global(env, &global), undefined);
449     napi_value json = nullptr;
450     NAPI_CALL_BASE(env, napi_get_named_property(env, global, GLOBAL_JSON, &json), undefined);
451     napi_value stringify = nullptr;
452     NAPI_CALL_BASE(env, napi_get_named_property(env, json, GLOBAL_JSON_STRINGIFY, &stringify), undefined);
453     if (GetValueType(env, stringify) != napi_function) {
454         return undefined;
455     }
456 
457     napi_value res = nullptr;
458     napi_value argv[1] = {object};
459     NAPI_CALL_BASE(env, napi_call_function(env, json, stringify, 1, argv, &res), undefined);
460     return res;
461 }
462 
JsonParse(napi_env env,napi_value str)463 napi_value JsonParse(napi_env env, napi_value str)
464 {
465     napi_value undefined = GetUndefined(env);
466 
467     if (GetValueType(env, str) != napi_string) {
468         return undefined;
469     }
470 
471     napi_value global = nullptr;
472     NAPI_CALL_BASE(env, napi_get_global(env, &global), undefined);
473     napi_value json = nullptr;
474     NAPI_CALL_BASE(env, napi_get_named_property(env, global, GLOBAL_JSON, &json), undefined);
475     napi_value parse = nullptr;
476     NAPI_CALL_BASE(env, napi_get_named_property(env, json, GLOBAL_JSON_PARSE, &parse), undefined);
477     if (GetValueType(env, parse) != napi_function) {
478         return undefined;
479     }
480 
481     napi_value res = nullptr;
482     napi_value argv[1] = {str};
483     NAPI_CALL_BASE(env, napi_call_function(env, json, parse, 1, argv, &res), undefined);
484     return res;
485 }
486 
487 /* libuv */
CreateUvQueueWork(napi_env env,void * data,void (handler)(uv_work_t *,int status))488 void CreateUvQueueWork(napi_env env, void *data, void(handler)(uv_work_t *, int status))
489 {
490     uv_loop_s *loop = nullptr;
491     NAPI_CALL_RETURN_VOID(env, napi_get_uv_event_loop(env, &loop));
492 
493     auto work = new uv_work_t;
494     work->data = data;
495 
496     (void)uv_queue_work(
497         loop, work, [](uv_work_t *) {}, handler);
498 }
499 
500 /* scope */
OpenScope(napi_env env)501 napi_handle_scope OpenScope(napi_env env)
502 {
503     napi_handle_scope scope = nullptr;
504     NAPI_CALL(env, napi_open_handle_scope(env, &scope));
505     return scope;
506 }
507 
CloseScope(napi_env env,napi_handle_scope scope)508 void CloseScope(napi_env env, napi_handle_scope scope)
509 {
510     (void)napi_close_handle_scope(env, scope);
511 }
512 
CreateUvQueueWorkEnhanced(napi_env env,void * data,void (* handler)(napi_env env,napi_status status,void * data))513 void CreateUvQueueWorkEnhanced(napi_env env, void *data, void (*handler)(napi_env env, napi_status status, void *data))
514 {
515     uv_loop_s *loop = nullptr;
516     NAPI_CALL_RETURN_VOID(env, napi_get_uv_event_loop(env, &loop));
517 
518     class WorkData {
519     public:
520         WorkData() = delete;
521 
522         WorkData(napi_env env, void *data, void (*handler)(napi_env env, napi_status status, void *data))
523             : env_(env), data_(data), handler_(handler)
524         {
525         }
526 
527         napi_env env_;
528         void *data_;
529         void (*handler_)(napi_env env, napi_status status, void *data);
530     };
531 
532     auto workData = new WorkData(env, data, handler);
533 
534     auto work = new uv_work_t;
535     work->data = reinterpret_cast<void *>(workData);
536 
537     auto callback = [](uv_work_t *work, int status) {
538         auto workData = static_cast<WorkData *>(work->data);
539         if (!workData) {
540             delete work;
541             return;
542         }
543 
544         if (!workData->env_ || !workData->data_ || !workData->handler_) {
545             delete workData;
546             delete work;
547             return;
548         }
549 
550         napi_env env = workData->env_;
551         auto closeScope = [env](napi_handle_scope scope) { NapiUtils::CloseScope(env, scope); };
552         std::unique_ptr<napi_handle_scope__, decltype(closeScope)> scope(NapiUtils::OpenScope(env), closeScope);
553 
554         workData->handler_(workData->env_, static_cast<napi_status>(status), workData->data_);
555 
556         delete workData;
557         delete work;
558     };
559 
560     (void)uv_queue_work(
561         loop, work, [](uv_work_t *) {}, callback);
562 }
563 
564 /* error */
CreateErrorMessage(napi_env env,int32_t errorCode,const std::string & errorMessage)565 napi_value CreateErrorMessage(napi_env env, int32_t errorCode, const std::string &errorMessage)
566 {
567     napi_value result = nullptr;
568     result = CreateObject(env);
569     SetNamedProperty(env, result, CODE, CreateInt32(env, errorCode));
570     SetNamedProperty(env, result, MSG, CreateStringUtf8(env, errorMessage));
571     return result;
572 }
573 } // namespace OHOS::NetStack::NapiUtils
574