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 #include "js_plugin_util.h"
16 
17 #include <cinttypes>
18 #include <cstring>
19 
20 #include "native_value.h"
21 #include "securec.h"
22 
23 #include "core/common/container.h"
24 
25 namespace OHOS::Ace::Napi {
26 constexpr int NAPI_ACE_ERR_NO_ERROR = 0;
27 constexpr int ACE_ARGS_TWO = 2;
28 constexpr int ACE_PARAM0 = 0;
29 constexpr int ACE_PARAM1 = 1;
30 
31 bool AceToJson(napi_env env, napi_value param, Json::Value& jsonObject);
32 napi_value ParseJsonToKVObject(napi_env env, Json::Value& jsonObject);
33 napi_value ParseJsonItem(napi_env env, Json::Value& item);
34 
AceIsTypeForNapiValue(napi_env env,napi_value param,napi_valuetype expectType)35 bool AceIsTypeForNapiValue(napi_env env, napi_value param, napi_valuetype expectType)
36 {
37     napi_valuetype valueType = napi_undefined;
38 
39     if (napi_typeof(env, param, &valueType) != napi_ok) {
40         return false;
41     }
42 
43     return valueType == expectType;
44 }
45 
AceIsArrayForNapiValue(napi_env env,napi_value param,uint32_t & arraySize)46 bool AceIsArrayForNapiValue(napi_env env, napi_value param, uint32_t& arraySize)
47 {
48     bool isArray = false;
49     arraySize = 0;
50 
51     if (napi_is_array(env, param, &isArray) != napi_ok || isArray == false) {
52         return false;
53     }
54 
55     if (napi_get_array_length(env, param, &arraySize) != napi_ok) {
56         return false;
57     }
58     return true;
59 }
60 
AceWrapVoidToJS(napi_env env)61 napi_value AceWrapVoidToJS(napi_env env)
62 {
63     napi_value result = nullptr;
64     NAPI_CALL(env, napi_get_null(env, &result));
65     return result;
66 }
67 
AceWrapUndefinedToJS(napi_env env)68 napi_value AceWrapUndefinedToJS(napi_env env)
69 {
70     napi_value result = nullptr;
71     NAPI_CALL(env, napi_get_undefined(env, &result));
72     return result;
73 }
74 
AceCreateJSObject(napi_env env)75 napi_value AceCreateJSObject(napi_env env)
76 {
77     napi_value result = nullptr;
78     NAPI_CALL(env, napi_create_object(env, &result));
79     return result;
80 }
81 
AceWrapInt32ToJS(napi_env env,int32_t value)82 napi_value AceWrapInt32ToJS(napi_env env, int32_t value)
83 {
84     napi_value result = nullptr;
85     NAPI_CALL(env, napi_create_int32(env, value, &result));
86     return result;
87 }
88 
AceUnwrapInt32FromJS(napi_env env,napi_value param,int defaultValue)89 int AceUnwrapInt32FromJS(napi_env env, napi_value param, int defaultValue)
90 {
91     int value = defaultValue;
92     if (napi_get_value_int32(env, param, &value) == napi_ok) {
93         return value;
94     } else {
95         return defaultValue;
96     }
97 }
98 
AceUnwrapInt32FromJS2(napi_env env,napi_value param,int & value)99 bool AceUnwrapInt32FromJS2(napi_env env, napi_value param, int& value)
100 {
101     bool result = false;
102     if (napi_get_value_int32(env, param, &value) == napi_ok) {
103         result = true;
104     }
105     return result;
106 }
107 
AceWrapLongToJS(napi_env env,int64_t value)108 napi_value AceWrapLongToJS(napi_env env, int64_t value)
109 {
110     napi_value result = nullptr;
111     NAPI_CALL(env, napi_create_int32(env, value, &result));
112     return result;
113 }
114 
AceUnwrapLongFromJS(napi_env env,napi_value param,int64_t defaultValue)115 int64_t AceUnwrapLongFromJS(napi_env env, napi_value param, int64_t defaultValue)
116 {
117     int value = 0;
118     if (napi_get_value_int32(env, param, &value) == napi_ok) {
119         return value;
120     } else {
121         return defaultValue;
122     }
123 }
124 
AceUnwrapLongFromJS2(napi_env env,napi_value param,int64_t & value)125 bool AceUnwrapLongFromJS2(napi_env env, napi_value param, int64_t& value)
126 {
127     bool result = false;
128     int natValue = 0;
129     if (napi_get_value_int32(env, param, &natValue) == napi_ok) {
130         value = natValue;
131         result = true;
132     }
133     return result;
134 }
135 
AceWrapInt64ToJS(napi_env env,int64_t value)136 napi_value AceWrapInt64ToJS(napi_env env, int64_t value)
137 {
138     napi_value result = nullptr;
139     NAPI_CALL(env, napi_create_int64(env, value, &result));
140     return result;
141 }
142 
AceUnwrapInt64FromJS(napi_env env,napi_value param,int64_t defaultValue)143 int64_t AceUnwrapInt64FromJS(napi_env env, napi_value param, int64_t defaultValue)
144 {
145     int64_t value = defaultValue;
146     if (napi_get_value_int64(env, param, &value) == napi_ok) {
147         return value;
148     } else {
149         return defaultValue;
150     }
151 }
152 
AceUnwrapInt64FromJS2(napi_env env,napi_value param,int64_t & value)153 bool AceUnwrapInt64FromJS2(napi_env env, napi_value param, int64_t& value)
154 {
155     bool result = false;
156     if (napi_get_value_int64(env, param, &value) == napi_ok) {
157         result = true;
158     }
159     return result;
160 }
161 
AceWrapBoolToJS(napi_env env,bool value)162 napi_value AceWrapBoolToJS(napi_env env, bool value)
163 {
164     napi_value result = nullptr;
165     NAPI_CALL(env, napi_get_boolean(env, value, &result));
166     return result;
167 }
168 
AceUnwrapBoolFromJS(napi_env env,napi_value param,bool defaultValue)169 bool AceUnwrapBoolFromJS(napi_env env, napi_value param, bool defaultValue)
170 {
171     bool value = defaultValue;
172     if (napi_get_value_bool(env, param, &value) == napi_ok) {
173         return value;
174     } else {
175         return defaultValue;
176     }
177 }
178 
AceUnwrapBoolFromJS2(napi_env env,napi_value param,bool & value)179 bool AceUnwrapBoolFromJS2(napi_env env, napi_value param, bool& value)
180 {
181     bool result = false;
182     if (napi_get_value_bool(env, param, &value) == napi_ok) {
183         result = true;
184     }
185     return result;
186 }
187 
AceWrapDoubleToJS(napi_env env,double value)188 napi_value AceWrapDoubleToJS(napi_env env, double value)
189 {
190     napi_value result = nullptr;
191     NAPI_CALL(env, napi_create_double(env, value, &result));
192     return result;
193 }
194 
AceUnwrapDoubleFromJS(napi_env env,napi_value param,double defaultValue)195 double AceUnwrapDoubleFromJS(napi_env env, napi_value param, double defaultValue)
196 {
197     double value = defaultValue;
198     if (napi_get_value_double(env, param, &value) == napi_ok) {
199         return value;
200     } else {
201         return defaultValue;
202     }
203 }
204 
AceUnwrapDoubleFromJS2(napi_env env,napi_value param,double & value)205 bool AceUnwrapDoubleFromJS2(napi_env env, napi_value param, double& value)
206 {
207     bool result = false;
208     if (napi_get_value_double(env, param, &value) == napi_ok) {
209         result = true;
210     }
211     return result;
212 }
213 
AceWrapStringToJS(napi_env env,const std::string & value)214 napi_value AceWrapStringToJS(napi_env env, const std::string& value)
215 {
216     napi_value result = nullptr;
217     NAPI_CALL(env, napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result));
218     return result;
219 }
220 
AceUnwrapStringFromJS(napi_env env,napi_value param,const std::string & defaultValue)221 std::string AceUnwrapStringFromJS(napi_env env, napi_value param, const std::string& defaultValue)
222 {
223     size_t size = 0;
224     if (napi_get_value_string_utf8(env, param, nullptr, 0, &size) != napi_ok) {
225         return defaultValue;
226     }
227 
228     std::string value("");
229     if (size == 0) {
230         return defaultValue;
231     }
232 
233     char* buf = new (std::nothrow) char[size + 1];
234     if (buf == nullptr) {
235         return value;
236     }
237     if (memset_s(buf, size + 1, 0, size + 1) != EOK) {
238         delete[] buf;
239         buf = nullptr;
240         return value;
241     }
242 
243     bool rev = napi_get_value_string_utf8(env, param, buf, size + 1, &size) == napi_ok;
244     if (rev) {
245         value = buf;
246     } else {
247         value = defaultValue;
248     }
249 
250     delete[] buf;
251     buf = nullptr;
252     return value;
253 }
254 
AceUnwrapStringFromJS2(napi_env env,napi_value param,std::string & value)255 bool AceUnwrapStringFromJS2(napi_env env, napi_value param, std::string& value)
256 {
257     value = "";
258     size_t size = 0;
259     if (napi_get_value_string_utf8(env, param, nullptr, 0, &size) != napi_ok) {
260         return false;
261     }
262 
263     if (size == 0) {
264         return true;
265     }
266 
267     char* buf = new (std::nothrow) char[size + 1];
268     if (buf == nullptr) {
269         return false;
270     }
271     if (memset_s(buf, (size + 1), 0, (size + 1)) != EOK) {
272         delete[] buf;
273         buf = nullptr;
274         return false;
275     }
276 
277     bool rev = napi_get_value_string_utf8(env, param, buf, size + 1, &size) == napi_ok;
278     if (rev) {
279         value = buf;
280     }
281     delete[] buf;
282     buf = nullptr;
283     return rev;
284 }
285 
AceWrapArrayInt32ToJS(napi_env env,const std::vector<int> & value)286 napi_value AceWrapArrayInt32ToJS(napi_env env, const std::vector<int>& value)
287 {
288     napi_value jsArray = nullptr;
289     napi_value jsValue = nullptr;
290     uint32_t index = 0;
291 
292     NAPI_CALL(env, napi_create_array(env, &jsArray));
293     for (uint32_t i = 0; i < value.size(); i++) {
294         jsValue = nullptr;
295         if (napi_create_int32(env, value[i], &jsValue) == napi_ok) {
296             if (napi_set_element(env, jsArray, index, jsValue) == napi_ok) {
297                 index++;
298             }
299         }
300     }
301     return jsArray;
302 }
303 
AceUnwrapArrayInt32FromJS(napi_env env,napi_value param,std::vector<int> & value)304 bool AceUnwrapArrayInt32FromJS(napi_env env, napi_value param, std::vector<int>& value)
305 {
306     uint32_t arraySize = 0;
307     napi_value jsValue = nullptr;
308     int natValue = 0;
309 
310     if (!AceIsArrayForNapiValue(env, param, arraySize)) {
311         return false;
312     }
313 
314     value.clear();
315     for (uint32_t i = 0; i < arraySize; i++) {
316         jsValue = nullptr;
317         natValue = 0;
318         if (napi_get_element(env, param, i, &jsValue) != napi_ok) {
319             return false;
320         }
321 
322         if (!AceUnwrapInt32FromJS2(env, jsValue, natValue)) {
323             return false;
324         }
325 
326         value.push_back(natValue);
327     }
328     return true;
329 }
330 
AceWrapArrayLongToJS(napi_env env,const std::vector<int64_t> & value)331 napi_value AceWrapArrayLongToJS(napi_env env, const std::vector<int64_t>& value)
332 {
333     napi_value jsArray = nullptr;
334     napi_value jsValue = nullptr;
335     uint32_t index = 0;
336 
337     NAPI_CALL(env, napi_create_array(env, &jsArray));
338     for (uint32_t i = 0; i < value.size(); i++) {
339         jsValue = nullptr;
340         if (napi_create_int32(env, (int)(value[i]), &jsValue) == napi_ok) {
341             if (napi_set_element(env, jsArray, index, jsValue) == napi_ok) {
342                 index++;
343             }
344         }
345     }
346     return jsArray;
347 }
348 
AceUnwrapArrayLongFromJS(napi_env env,napi_value param,std::vector<int64_t> & value)349 bool AceUnwrapArrayLongFromJS(napi_env env, napi_value param, std::vector<int64_t>& value)
350 {
351     uint32_t arraySize = 0;
352     napi_value jsValue = nullptr;
353     int64_t natValue = 0;
354 
355     if (!AceIsArrayForNapiValue(env, param, arraySize)) {
356         return false;
357     }
358 
359     value.clear();
360     for (uint32_t i = 0; i < arraySize; i++) {
361         jsValue = nullptr;
362         natValue = 0;
363         if (napi_get_element(env, param, i, &jsValue) != napi_ok) {
364             return false;
365         }
366 
367         if (!AceUnwrapLongFromJS2(env, jsValue, natValue)) {
368             return false;
369         }
370 
371         value.push_back(natValue);
372     }
373     return true;
374 }
375 
AceWrapArrayInt64ToJS(napi_env env,const std::vector<int64_t> & value)376 napi_value AceWrapArrayInt64ToJS(napi_env env, const std::vector<int64_t>& value)
377 {
378     napi_value jsArray = nullptr;
379     napi_value jsValue = nullptr;
380     uint32_t index = 0;
381 
382     NAPI_CALL(env, napi_create_array(env, &jsArray));
383     for (uint32_t i = 0; i < value.size(); i++) {
384         jsValue = nullptr;
385         if (napi_create_int64(env, value[i], &jsValue) == napi_ok) {
386             if (napi_set_element(env, jsArray, index, jsValue) == napi_ok) {
387                 index++;
388             }
389         }
390     }
391     return jsArray;
392 }
393 
AceUnwrapArrayInt64FromJS(napi_env env,napi_value param,std::vector<int64_t> & value)394 bool AceUnwrapArrayInt64FromJS(napi_env env, napi_value param, std::vector<int64_t>& value)
395 {
396     uint32_t arraySize = 0;
397     napi_value jsValue = nullptr;
398     int64_t natValue = 0;
399 
400     if (!AceIsArrayForNapiValue(env, param, arraySize)) {
401         return false;
402     }
403 
404     value.clear();
405     for (uint32_t i = 0; i < arraySize; i++) {
406         jsValue = nullptr;
407         natValue = 0;
408         if (napi_get_element(env, param, i, &jsValue) != napi_ok) {
409             return false;
410         }
411 
412         if (!AceUnwrapInt64FromJS2(env, jsValue, natValue)) {
413             return false;
414         }
415 
416         value.push_back(natValue);
417     }
418     return true;
419 }
420 
AceWrapArrayDoubleToJS(napi_env env,const std::vector<double> & value)421 napi_value AceWrapArrayDoubleToJS(napi_env env, const std::vector<double>& value)
422 {
423     napi_value jsArray = nullptr;
424     napi_value jsValue = nullptr;
425     uint32_t index = 0;
426 
427     NAPI_CALL(env, napi_create_array(env, &jsArray));
428     for (uint32_t i = 0; i < value.size(); i++) {
429         jsValue = nullptr;
430         if (napi_create_double(env, value[i], &jsValue) == napi_ok) {
431             if (napi_set_element(env, jsArray, index, jsValue) == napi_ok) {
432                 index++;
433             }
434         }
435     }
436     return jsArray;
437 }
438 
AceUnwrapArrayDoubleFromJS(napi_env env,napi_value param,std::vector<double> & value)439 bool AceUnwrapArrayDoubleFromJS(napi_env env, napi_value param, std::vector<double>& value)
440 {
441     uint32_t arraySize = 0;
442     napi_value jsValue = nullptr;
443     double natValue = 0;
444 
445     if (!AceIsArrayForNapiValue(env, param, arraySize)) {
446         return false;
447     }
448 
449     value.clear();
450     for (uint32_t i = 0; i < arraySize; i++) {
451         jsValue = nullptr;
452         natValue = 0;
453         if (napi_get_element(env, param, i, &jsValue) != napi_ok) {
454             return false;
455         }
456 
457         if (!AceUnwrapDoubleFromJS2(env, jsValue, natValue)) {
458             return false;
459         }
460 
461         value.push_back(natValue);
462     }
463     return true;
464 }
465 
AceWrapArrayBoolToJS(napi_env env,const std::vector<bool> & value)466 napi_value AceWrapArrayBoolToJS(napi_env env, const std::vector<bool>& value)
467 {
468     napi_value jsArray = nullptr;
469     napi_value jsValue = nullptr;
470     uint32_t index = 0;
471 
472     NAPI_CALL(env, napi_create_array(env, &jsArray));
473     for (uint32_t i = 0; i < value.size(); i++) {
474         jsValue = nullptr;
475         if (napi_get_boolean(env, value[i], &jsValue) == napi_ok) {
476             if (napi_set_element(env, jsArray, index, jsValue) == napi_ok) {
477                 index++;
478             }
479         }
480     }
481     return jsArray;
482 }
483 
AceUnwrapArrayBoolFromJS(napi_env env,napi_value param,std::vector<bool> & value)484 bool AceUnwrapArrayBoolFromJS(napi_env env, napi_value param, std::vector<bool>& value)
485 {
486     uint32_t arraySize = 0;
487     napi_value jsValue = nullptr;
488     bool natValue = 0;
489 
490     if (!AceIsArrayForNapiValue(env, param, arraySize)) {
491         return false;
492     }
493 
494     value.clear();
495     for (uint32_t i = 0; i < arraySize; i++) {
496         jsValue = nullptr;
497         natValue = 0;
498         if (napi_get_element(env, param, i, &jsValue) != napi_ok) {
499             return false;
500         }
501 
502         if (!AceUnwrapBoolFromJS2(env, jsValue, natValue)) {
503             return false;
504         }
505 
506         value.push_back(natValue);
507     }
508     return true;
509 }
510 
AceWrapArrayStringToJS(napi_env env,const std::vector<std::string> & value)511 napi_value AceWrapArrayStringToJS(napi_env env, const std::vector<std::string>& value)
512 {
513     napi_value jsArray = nullptr;
514     napi_value jsValue = nullptr;
515     uint32_t index = 0;
516 
517     NAPI_CALL(env, napi_create_array(env, &jsArray));
518     for (uint32_t i = 0; i < value.size(); i++) {
519         jsValue = nullptr;
520         if (napi_create_string_utf8(env, value[i].c_str(), NAPI_AUTO_LENGTH, &jsValue) == napi_ok) {
521             if (napi_set_element(env, jsArray, index, jsValue) == napi_ok) {
522                 index++;
523             }
524         }
525     }
526     return jsArray;
527 }
528 
AceUnwrapArrayStringFromJS(napi_env env,napi_value param,std::vector<std::string> & value)529 bool AceUnwrapArrayStringFromJS(napi_env env, napi_value param, std::vector<std::string>& value)
530 {
531     uint32_t arraySize = 0;
532     napi_value jsValue = nullptr;
533     std::string natValue("");
534 
535     if (!AceIsArrayForNapiValue(env, param, arraySize)) {
536         return false;
537     }
538 
539     value.clear();
540     for (uint32_t i = 0; i < arraySize; i++) {
541         jsValue = nullptr;
542         natValue = "";
543         if (napi_get_element(env, param, i, &jsValue) != napi_ok) {
544             return false;
545         }
546 
547         if (!AceUnwrapStringFromJS2(env, jsValue, natValue)) {
548             return false;
549         }
550 
551         value.push_back(natValue);
552     }
553     return true;
554 }
555 
AceKVObjectToString(napi_env env,napi_value param,std::string & value)556 bool AceKVObjectToString(napi_env env, napi_value param, std::string& value)
557 {
558     if (!AceIsTypeForNapiValue(env, param, napi_object)) {
559         return false;
560     }
561 
562     napi_value globalValue;
563     napi_get_global(env, &globalValue);
564     napi_value jsonValue;
565     napi_get_named_property(env, globalValue, "JSON", &jsonValue);
566     napi_value stringifyValue;
567     napi_get_named_property(env, jsonValue, "stringify", &stringifyValue);
568     napi_value funcArgv[1] = { param };
569     napi_value returnValue = nullptr;
570     napi_call_function(env, jsonValue, stringifyValue, 1, funcArgv, &returnValue);
571     size_t buffSize = 0;
572     napi_status status = napi_get_value_string_utf8(env, returnValue, nullptr, 0, &buffSize);
573     if (status != napi_ok || buffSize == 0) {
574         return false;
575     }
576     std::unique_ptr<char[]> paramsChar = std::make_unique<char[]>(buffSize + 1);
577     size_t ret = 0;
578     napi_get_value_string_utf8(env, returnValue, paramsChar.get(), buffSize + 1, &ret);
579     value = paramsChar.get();
580     return true;
581 }
582 
AceStringToKVObject(napi_env env,const std::string & jsonString)583 napi_value AceStringToKVObject(napi_env env, const std::string& jsonString)
584 {
585     if (jsonString.empty()) {
586         return nullptr;
587     }
588 
589     napi_value globalValue;
590     napi_get_global(env, &globalValue);
591     napi_value jsonValue;
592     napi_get_named_property(env, globalValue, "JSON", &jsonValue);
593     napi_value parseValue;
594     napi_get_named_property(env, jsonValue, "parse", &parseValue);
595     napi_value gridInfoNApi;
596     napi_create_string_utf8(env, jsonString.c_str(), NAPI_AUTO_LENGTH, &gridInfoNApi);
597     napi_value funcArgv[1] = { gridInfoNApi };
598     napi_value result;
599     napi_call_function(env, jsonValue, parseValue, 1, funcArgv, &result);
600     napi_valuetype valueType = napi_undefined;
601     napi_typeof(env, result, &valueType);
602     if (valueType != napi_object) {
603         return nullptr;
604     }
605     return result;
606 }
607 
AceInitComplexArrayData(ACEComplexArrayData & value)608 void AceInitComplexArrayData(ACEComplexArrayData& value)
609 {
610     value.intList.clear();
611     value.longList.clear();
612     value.boolList.clear();
613     value.doubleList.clear();
614     value.stringList.clear();
615 }
616 
AceTranscomplex(ACEComplexArrayData & value)617 void AceTranscomplex(ACEComplexArrayData& value)
618 {
619     if (value.intList.size() > 0) {
620         for (size_t j = 0; j < value.intList.size(); j++) {
621             value.doubleList.push_back(value.intList[j]);
622         }
623         value.intList.clear();
624     }
625 }
626 
AceUnwrapNumberComplexFromJS(napi_env env,napi_value jsValue,bool & isDouble,ACEComplexArrayData & value)627 void AceUnwrapNumberComplexFromJS(napi_env env, napi_value jsValue, bool& isDouble, ACEComplexArrayData& value)
628 {
629     int32_t elementInt32 = 0;
630     double elementDouble = 0.0;
631     if (isDouble) {
632         if (napi_get_value_double(env, jsValue, &elementDouble) == napi_ok) {
633             value.doubleList.push_back(elementDouble);
634         }
635     } else {
636         bool isReadValue32 = napi_get_value_int32(env, jsValue, &elementInt32) == napi_ok;
637         bool isReadDouble = napi_get_value_double(env, jsValue, &elementDouble) == napi_ok;
638         if (isReadValue32 && isReadDouble) {
639             if (abs(elementDouble - elementInt32 * 1.0) > 0.0) {
640                 isDouble = true;
641                 AceTranscomplex(value);
642                 value.doubleList.push_back(elementDouble);
643             } else {
644                 value.intList.push_back(elementInt32);
645             }
646         } else if (isReadValue32) {
647             value.intList.push_back(elementInt32);
648         } else if (isReadDouble) {
649             isDouble = true;
650             AceTranscomplex(value);
651             value.doubleList.push_back(elementDouble);
652         }
653     }
654 }
655 
AceUnwrapArrayComplexFromJS(napi_env env,napi_value param,ACEComplexArrayData & value)656 bool AceUnwrapArrayComplexFromJS(napi_env env, napi_value param, ACEComplexArrayData& value)
657 {
658     uint32_t arraySize = 0;
659     if (!AceIsArrayForNapiValue(env, param, arraySize)) {
660         return false;
661     }
662 
663     AceInitComplexArrayData(value);
664     napi_valuetype valueType = napi_undefined;
665     napi_value jsValue = nullptr;
666     bool isDouble = false;
667 
668     for (uint32_t i = 0; i < arraySize; i++) {
669         jsValue = nullptr;
670         valueType = napi_undefined;
671         NAPI_CALL_BASE(env, napi_get_element(env, param, i, &jsValue), false);
672         NAPI_CALL_BASE(env, napi_typeof(env, jsValue, &valueType), false);
673         switch (valueType) {
674             case napi_string: {
675                 std::string elementValue("");
676                 if (AceUnwrapStringFromJS2(env, jsValue, elementValue)) {
677                     value.stringList.push_back(elementValue);
678                 } else {
679                     return false;
680                 }
681                 break;
682             }
683             case napi_boolean: {
684                 bool elementValue = false;
685                 NAPI_CALL_BASE(env, napi_get_value_bool(env, jsValue, &elementValue), false);
686                 value.boolList.push_back(elementValue);
687                 break;
688             }
689             case napi_number:
690                 AceUnwrapNumberComplexFromJS(env, jsValue, isDouble, value);
691                 break;
692             default:
693                 break;
694         }
695     }
696     return true;
697 }
698 
AceIsSameFuncFromJS(ACECallbackInfo & left,ACECallbackInfo & right)699 bool AceIsSameFuncFromJS(ACECallbackInfo& left, ACECallbackInfo& right)
700 {
701     if (left.env == nullptr && right.env == nullptr) {
702         return true;
703     }
704     if (left.env != right.env || left.containerId != right.containerId) {
705         return false;
706     }
707     if (left.callback == nullptr && right.callback == nullptr) {
708         return true;
709     }
710 
711     bool result = false;
712     napi_value leftFunc = nullptr;
713     napi_value rightFunc = nullptr;
714     napi_get_reference_value(left.env, left.callback, &leftFunc);
715     napi_get_reference_value(right.env, right.callback, &rightFunc);
716     napi_strict_equals(left.env, leftFunc, rightFunc, &result);
717     return result;
718 }
719 
720 /**
721  * @brief Indicates the specified attribute exists in the object passed by JS.
722  *
723  * @param env The environment that the Node-API call is invoked under.
724  * @param jsObject Indicates object passed by JS.
725  * @param propertyName Indicates the name of the property.
726  *
727  * @return Returns true if the attribute exists, else returns false.
728  */
AceIsExistsByPropertyName(napi_env env,napi_value jsObject,const char * propertyName)729 bool AceIsExistsByPropertyName(napi_env env, napi_value jsObject, const char* propertyName)
730 {
731     bool result = false;
732     if (napi_has_named_property(env, jsObject, propertyName, &result) == napi_ok) {
733         return result;
734     } else {
735         return false;
736     }
737 }
738 
739 /**
740  * @brief Get the JSValue of the specified name from the JS object.
741  *
742  * @param env The environment that the Node-API call is invoked under.
743  * @param jsObject Indicates object passed by JS.
744  * @param propertyName Indicates the name of the property.
745  * @param expectType Indicates expected JS data type.
746  *
747  * @return Return the property value of the specified property name int jsObject on success, otherwise return
748  * nullptr.
749  */
AceGetPropertyValueByPropertyName(napi_env env,napi_value jsObject,const char * propertyName,napi_valuetype expectType)750 napi_value AceGetPropertyValueByPropertyName(
751     napi_env env, napi_value jsObject, const char* propertyName, napi_valuetype expectType)
752 {
753     napi_value value = nullptr;
754     if (AceIsExistsByPropertyName(env, jsObject, propertyName) == false) {
755         return nullptr;
756     }
757 
758     if (napi_get_named_property(env, jsObject, propertyName, &value) != napi_ok) {
759         return nullptr;
760     }
761 
762     if (!AceIsTypeForNapiValue(env, value, expectType)) {
763         return nullptr;
764     }
765 
766     return value;
767 }
768 
AceSetPropertyValueByPropertyName(napi_env env,napi_value jsObject,const char * propertyName,napi_value value)769 bool AceSetPropertyValueByPropertyName(napi_env env, napi_value jsObject, const char* propertyName, napi_value value)
770 {
771     if (value != nullptr && propertyName != nullptr) {
772         NAPI_CALL_BASE(env, napi_set_named_property(env, jsObject, propertyName, value), false);
773         return true;
774     }
775     return false;
776 }
777 
778 /**
779  * @brief Get the native number(int32) from the JSObject of the given property name.
780  *
781  * @param env The environment that the Node-API call is invoked under.
782  * @param jsObject Indicates object passed by JS.
783  * @param propertyName Indicates the name of the property.
784  * @param value Indicates the returned native value.
785  *
786  * @return Return true if successful, else return false.
787  */
AceUnwrapInt32ByPropertyName(napi_env env,napi_value jsObject,const char * propertyName,int32_t & value)788 bool AceUnwrapInt32ByPropertyName(napi_env env, napi_value jsObject, const char* propertyName, int32_t& value)
789 {
790     napi_value jsValue = AceGetPropertyValueByPropertyName(env, jsObject, propertyName, napi_number);
791     if (jsValue != nullptr) {
792         return AceUnwrapInt32FromJS2(env, jsValue, value);
793     } else {
794         return false;
795     }
796 }
797 
798 /**
799  * @brief Get the native number(double) from the JSObject of the given property name.
800  *
801  * @param env The environment that the Node-API call is invoked under.
802  * @param jsObject Indicates object passed by JS.
803  * @param propertyName Indicates the name of the property.
804  * @param value Indicates the returned native value.
805  *
806  * @return Return true if successful, else return false.
807  */
AceUnwrapDoubleByPropertyName(napi_env env,napi_value jsObject,const char * propertyName,double & value)808 bool AceUnwrapDoubleByPropertyName(napi_env env, napi_value jsObject, const char* propertyName, double& value)
809 {
810     napi_value jsValue = AceGetPropertyValueByPropertyName(env, jsObject, propertyName, napi_number);
811     if (jsValue != nullptr) {
812         return AceUnwrapDoubleFromJS2(env, jsValue, value);
813     } else {
814         return false;
815     }
816 }
817 
818 /**
819  * @brief Get the native boolean from the JSObject of the given property name.
820  *
821  * @param env The environment that the Node-API call is invoked under.
822  * @param jsObject Indicates object passed by JS.
823  * @param propertyName Indicates the name of the property.
824  * @param value Indicates the returned native value.
825  *
826  * @return Return true if successful, else return false.
827  */
AceUnwrapBooleanByPropertyName(napi_env env,napi_value jsObject,const char * propertyName,bool & value)828 bool AceUnwrapBooleanByPropertyName(napi_env env, napi_value jsObject, const char* propertyName, bool& value)
829 {
830     napi_value jsValue = AceGetPropertyValueByPropertyName(env, jsObject, propertyName, napi_boolean);
831     if (jsValue != nullptr) {
832         return AceUnwrapBoolFromJS2(env, jsValue, value);
833     } else {
834         return false;
835     }
836 }
837 
AceUnwrapBooleanArrayByPropertyName(napi_env env,napi_value jsObject,const char * propertyName,std::vector<bool> & value)838 bool AceUnwrapBooleanArrayByPropertyName(
839     napi_env env, napi_value jsObject, const char* propertyName, std::vector<bool>& value)
840 {
841     napi_value jsArray = AceGetPropertyValueByPropertyName(env, jsObject, propertyName, napi_object);
842     if (jsArray == nullptr) {
843         return false;
844     }
845 
846     return AceUnwrapArrayBoolFromJS(env, jsArray, value);
847 }
848 
849 /**
850  * @brief Get the native string from the JSObject of the given property name.
851  *
852  * @param env The environment that the Node-API call is invoked under.
853  * @param jsObject Indicates object passed by JS.
854  * @param propertyName Indicates the name of the property.
855  * @param value Indicates the returned native value.
856  *
857  * @return Return true if successful, else return false.
858  */
AceUnwrapStringByPropertyName(napi_env env,napi_value jsObject,const char * propertyName,std::string & value)859 bool AceUnwrapStringByPropertyName(napi_env env, napi_value jsObject, const char* propertyName, std::string& value)
860 {
861     napi_value jsValue = AceGetPropertyValueByPropertyName(env, jsObject, propertyName, napi_string);
862     if (jsValue != nullptr) {
863         return AceUnwrapStringFromJS2(env, jsValue, value);
864     } else {
865         return false;
866     }
867 }
868 
AceUnwrapStringArrayByPropertyName(napi_env env,napi_value jsObject,const char * propertyName,std::vector<std::string> & value)869 bool AceUnwrapStringArrayByPropertyName(
870     napi_env env, napi_value jsObject, const char* propertyName, std::vector<std::string>& value)
871 {
872     napi_value jsArray = AceGetPropertyValueByPropertyName(env, jsObject, propertyName, napi_object);
873     if (jsArray == nullptr) {
874         return false;
875     }
876 
877     return AceUnwrapArrayStringFromJS(env, jsArray, value);
878 }
879 
AceClearThreadReturnData(ACEThreadReturnData * data)880 void AceClearThreadReturnData(ACEThreadReturnData* data)
881 {
882     if (data != nullptr) {
883         data->data_type = TACENativeValueType::NVT_NONE;
884         data->int32_value = 0;
885         data->bool_value = false;
886         data->str_value = "";
887         data->double_value = 0.0;
888     }
889 }
890 
AceGetCallbackErrorValue(napi_env env,int errCode)891 napi_value AceGetCallbackErrorValue(napi_env env, int errCode)
892 {
893     napi_value jsObject = nullptr;
894     napi_value jsValue = nullptr;
895     NAPI_CALL(env, napi_create_int32(env, errCode, &jsValue));
896     NAPI_CALL(env, napi_create_object(env, &jsObject));
897     NAPI_CALL(env, napi_set_named_property(env, jsObject, "code", jsValue));
898     return jsObject;
899 }
900 
901 /**
902  * @brief Create asynchronous data.
903  *
904  * @param env The environment that the Node-API call is invoked under.
905  *
906  * @return Return a pointer to AsyncPermissionCallbackInfo on success, nullptr on failure
907  */
AceCreateAsyncJSCallbackInfo(napi_env env)908 ACEAsyncJSCallbackInfo* AceCreateAsyncJSCallbackInfo(napi_env env)
909 {
910     napi_value global = 0;
911     NAPI_CALL(env, napi_get_global(env, &global));
912 
913     napi_value abilityObj = 0;
914     NAPI_CALL(env, napi_get_named_property(env, global, "ability", &abilityObj));
915     Ability* ability = nullptr;
916     napi_valuetype valueType = napi_undefined;
917     NAPI_CALL(env, napi_typeof(env, abilityObj, &valueType));
918     if (valueType == napi_external) {
919         NAPI_CALL(env, napi_get_value_external(env, abilityObj, (void**)&ability));
920     }
921 
922     auto containerId = Container::CurrentId();
923     ACEAsyncJSCallbackInfo* asyncCallbackInfo = new (std::nothrow) ACEAsyncJSCallbackInfo {
924         .cbInfo = {
925             .env = env,
926             .callback = nullptr,
927             .containerId = containerId,
928         },
929         .ability = ability,
930         .deferred = nullptr,
931         .onRequestData = nullptr,
932         .onRequestCallbackOK = false,
933     };
934 
935     if (asyncCallbackInfo != nullptr) {
936         AceClearThreadReturnData(&asyncCallbackInfo->native_data);
937     }
938     return asyncCallbackInfo;
939 }
940 
AceFreeAsyncJSCallbackInfo(ACEAsyncJSCallbackInfo ** asyncCallbackInfo)941 void AceFreeAsyncJSCallbackInfo(ACEAsyncJSCallbackInfo** asyncCallbackInfo)
942 {
943     if (asyncCallbackInfo == nullptr) {
944         return;
945     }
946     if (*asyncCallbackInfo == nullptr) {
947         return;
948     }
949 
950     if ((*asyncCallbackInfo)->cbInfo.callback != nullptr && (*asyncCallbackInfo)->cbInfo.env != nullptr) {
951         napi_delete_reference((*asyncCallbackInfo)->cbInfo.env, (*asyncCallbackInfo)->cbInfo.callback);
952         (*asyncCallbackInfo)->cbInfo.callback = nullptr;
953         (*asyncCallbackInfo)->cbInfo.env = nullptr;
954     }
955 
956     delete (*asyncCallbackInfo);
957     *asyncCallbackInfo = nullptr;
958 }
959 
960 /**
961  * @brief Convert local data to JS data.
962  *
963  * @param env The environment that the Node-API call is invoked under.
964  * @param data The local data.
965  * @param value the JS data.
966  *
967  * @return The return value from NAPI C++ to JS for the module.
968  */
AceWrapThreadReturnData(napi_env env,const ACEThreadReturnData * data,napi_value * value)969 bool AceWrapThreadReturnData(napi_env env, const ACEThreadReturnData* data, napi_value* value)
970 {
971     if (data == nullptr || value == nullptr) {
972         return false;
973     }
974 
975     switch (data->data_type) {
976         case TACENativeValueType::NVT_UNDEFINED:
977             NAPI_CALL_BASE(env, napi_get_undefined(env, value), false);
978             break;
979         case TACENativeValueType::NVT_INT32:
980             NAPI_CALL_BASE(env, napi_create_int32(env, data->int32_value, value), false);
981             break;
982         case TACENativeValueType::NVT_BOOL:
983             NAPI_CALL_BASE(env, napi_get_boolean(env, data->bool_value, value), false);
984             break;
985         case TACENativeValueType::NVT_STRING:
986             NAPI_CALL_BASE(env, napi_create_string_utf8(env, data->str_value.c_str(), NAPI_AUTO_LENGTH, value), false);
987             break;
988         default:
989             NAPI_CALL_BASE(env, napi_get_null(env, value), false);
990             break;
991     }
992     return true;
993 }
994 
995 /**
996  * @brief Create asynchronous data.
997  *
998  * @param env The environment that the Node-API call is invoked under.
999  * @param param Parameter list.
1000  * @param callback Point to asynchronous processing of data.
1001  *
1002  * @return Return true successfully, otherwise return false.
1003  */
AceCreateAsyncCallback(napi_env env,napi_value param,ACEAsyncJSCallbackInfo * callback)1004 bool AceCreateAsyncCallback(napi_env env, napi_value param, ACEAsyncJSCallbackInfo* callback)
1005 {
1006     if (param == nullptr || callback == nullptr) {
1007         return false;
1008     }
1009 
1010     callback->cbInfo.callback = AceCreateCallbackRefFromJS(env, param);
1011     if (callback->cbInfo.callback == nullptr) {
1012         return false;
1013     }
1014 
1015     return true;
1016 }
1017 
AceCreateCallbackRefFromJS(napi_env env,napi_value param)1018 napi_ref AceCreateCallbackRefFromJS(napi_env env, napi_value param)
1019 {
1020     if (env == nullptr || param == nullptr) {
1021         return nullptr;
1022     }
1023 
1024     napi_valuetype valueType = napi_undefined;
1025     NAPI_CALL(env, napi_typeof(env, param, &valueType));
1026 
1027     if (valueType != napi_function) {
1028         return nullptr;
1029     }
1030 
1031     napi_ref callbackRef = nullptr;
1032     NAPI_CALL(env, napi_create_reference(env, param, 1, &callbackRef));
1033     return callbackRef;
1034 }
1035 
1036 /**
1037  * @brief The callback at the end of the asynchronous callback.
1038  *
1039  * @param env The environment that the Node-API call is invoked under.
1040  * @param data Point to asynchronous processing of data.
1041  */
AceCompleteAsyncCallbackWork(napi_env env,ACEAsyncJSCallbackInfo * asyncCallbackInfo)1042 void AceCompleteAsyncCallbackWork(napi_env env, ACEAsyncJSCallbackInfo* asyncCallbackInfo)
1043 {
1044     if (asyncCallbackInfo == nullptr) {
1045         return;
1046     }
1047 
1048     napi_value callback = 0;
1049     napi_value undefined = 0;
1050     napi_get_undefined(env, &undefined);
1051     napi_value callResult = 0;
1052     napi_value revParam[ACE_ARGS_TWO] = { nullptr };
1053 
1054     revParam[ACE_PARAM0] = AceGetCallbackErrorValue(env, asyncCallbackInfo->error_code);
1055     AceWrapThreadReturnData(env, &asyncCallbackInfo->native_data, &revParam[ACE_PARAM1]);
1056 
1057     if (asyncCallbackInfo->cbInfo.callback != nullptr) {
1058         napi_get_reference_value(env, asyncCallbackInfo->cbInfo.callback, &callback);
1059         napi_call_function(env, undefined, callback, ACE_ARGS_TWO, revParam, &callResult);
1060         napi_delete_reference(env, asyncCallbackInfo->cbInfo.callback);
1061     }
1062 
1063     delete asyncCallbackInfo;
1064     asyncCallbackInfo = nullptr;
1065 }
1066 
1067 /**
1068  * @brief The callback at the end of the Promise callback.
1069  *
1070  * @param env The environment that the Node-API call is invoked under.
1071  * @param data Point to asynchronous processing of data.
1072  */
AceCompletePromiseCallbackWork(napi_env env,ACEAsyncJSCallbackInfo * asyncCallbackInfo)1073 void AceCompletePromiseCallbackWork(napi_env env, ACEAsyncJSCallbackInfo* asyncCallbackInfo)
1074 {
1075     if (asyncCallbackInfo == nullptr) {
1076         return;
1077     }
1078 
1079     napi_value result = 0;
1080     if (asyncCallbackInfo->error_code == NAPI_ACE_ERR_NO_ERROR) {
1081         AceWrapThreadReturnData(env, &asyncCallbackInfo->native_data, &result);
1082         napi_resolve_deferred(env, asyncCallbackInfo->deferred, result);
1083     } else {
1084         result = AceGetCallbackErrorValue(env, asyncCallbackInfo->error_code);
1085         napi_reject_deferred(env, asyncCallbackInfo->deferred, result);
1086     }
1087     delete asyncCallbackInfo;
1088     asyncCallbackInfo = nullptr;
1089 }
1090 
1091 /**
1092  * @brief Set named property to obj by string
1093  *
1094  * @param jsObject Indicates object passed by JS.
1095  * @param propertyName Indicates the name of the object.
1096  * @param propName Indicates the name of the property.
1097  */
AceSetNamedPropertyByString(napi_env env,napi_value jsObject,const char * objName,const char * propName)1098 void AceSetNamedPropertyByString(napi_env env, napi_value jsObject, const char* objName, const char* propName)
1099 {
1100     napi_value prop = nullptr;
1101     napi_create_string_utf8(env, objName, NAPI_AUTO_LENGTH, &prop);
1102     napi_set_named_property(env, jsObject, propName, prop);
1103 }
1104 } // namespace OHOS::Ace::Napi
1105