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