1 /*
2  * Copyright (C) 2023 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 "nfc_napi_common_utils.h"
17 #include <cstring>
18 #include "loghelper.h"
19 #include "nfc_sdk_common.h"
20 #include "securec.h"
21 
22 namespace OHOS {
23 namespace NFC {
24 namespace KITS {
ParseString(napi_env env, std::string &param, napi_value args)25 bool ParseString(napi_env env, std::string &param, napi_value args)
26 {
27     napi_valuetype valuetype;
28     napi_typeof(env, args, &valuetype);
29 
30     DebugLog("param=%{public}d.", valuetype);
31     if (valuetype != napi_string) {
32         DebugLog("Wrong argument type. String expected.");
33         return false;
34     }
35     size_t size = 0;
36 
37     if (napi_get_value_string_utf8(env, args, nullptr, 0, &size) != napi_ok) {
38         ErrorLog("can not get string size");
39         param = "";
40         return false;
41     }
42     param.reserve(size + 1);
43     param.resize(size);
44     if (napi_get_value_string_utf8(env, args, param.data(), (size + 1), &size) != napi_ok) {
45         ErrorLog("can not get string value");
46         param = "";
47         return false;
48     }
49     return true;
50 }
ParseInt32(napi_env env, int32_t &param, napi_value args)51 bool ParseInt32(napi_env env, int32_t &param, napi_value args)
52 {
53     napi_valuetype valuetype;
54     napi_typeof(env, args, &valuetype);
55 
56     DebugLog("ParseInt32, valuetype %{public}d.", valuetype);
57     if (valuetype != napi_number) {
58         ErrorLog("Wrong argument type. Int32 expected.");
59         return false;
60     }
61     napi_get_value_int32(env, args, &param);
62     return true;
63 }
64 
ParseBool(napi_env env, bool &param, napi_value args)65 bool ParseBool(napi_env env, bool &param, napi_value args)
66 {
67     napi_valuetype valuetype;
68     napi_typeof(env, args, &valuetype);
69 
70     DebugLog("param=%{public}d.", valuetype);
71     if (valuetype != napi_boolean) {
72         ErrorLog("Wrong argument type. bool expected.");
73         return false;
74     }
75     napi_get_value_bool(env, args, &param);
76     return true;
77 }
78 
ParseBytesVector(napi_env env, std::vector<unsigned char> &vec, napi_value args)79 bool ParseBytesVector(napi_env env, std::vector<unsigned char> &vec, napi_value args)
80 {
81     bool isArray = false;
82     napi_status status = napi_is_array(env, args, &isArray);
83     if (status != napi_ok || !isArray) {
84         ErrorLog("ParseBytesVector, not array");
85         return false;
86     }
87     uint32_t arrayLength = 0;
88     napi_get_array_length(env, args, &arrayLength);
89     for (uint32_t i = 0; i < arrayLength; i++) {
90         napi_value element = nullptr;
91         napi_get_element(env, args, i, &element);
92 
93         napi_valuetype valueType = napi_undefined;
94         napi_typeof(env, element, &valueType);
95         if (valueType != napi_number) {
96             ErrorLog("ParseBytesVector, not number!");
97             return false;
98         }
99 
100         uint32_t byteValue = 0x0;
101         napi_get_value_uint32(env, element, &byteValue);
102         vec.push_back(static_cast<unsigned char>(byteValue));
103     }
104     return true;
105 }
106 
ParseUInt32Vector(napi_env& env, std::vector<uint32_t>& vec, napi_value &args)107 bool ParseUInt32Vector(napi_env& env, std::vector<uint32_t>& vec, napi_value &args)
108 {
109     bool isArray = false;
110     napi_status status = napi_is_array(env, args, &isArray);
111     if (status != napi_ok || !isArray) {
112         ErrorLog("ParseUInt32Vector: not array");
113         return false;
114     }
115     uint32_t arrayLen = 0;
116     napi_get_array_length(env, args, &arrayLen);
117     for (uint32_t i = 0; i < arrayLen; i++) {
118         napi_value element = nullptr;
119         napi_get_element(env, args, i, &element);
120 
121         napi_valuetype valueType = napi_undefined;
122         napi_typeof(env, element, &valueType);
123         if (valueType != napi_number) {
124             ErrorLog("ParseUInt32Vector, not number!");
125             return false;
126         }
127 
128         uint32_t uint32Value = 0;
129         napi_get_value_uint32(env, element, &uint32Value);
130         vec.push_back(static_cast<uint32_t>(uint32Value));
131     }
132     return true;
133 }
134 
ParseStringVector(napi_env &env, std::vector<std::string> &vec, napi_value &args, uint32_t maxLen)135 bool ParseStringVector(napi_env &env, std::vector<std::string> &vec, napi_value &args, uint32_t maxLen)
136 {
137     bool isArray = false;
138     napi_status status = napi_is_array(env, args, &isArray);
139     if (status != napi_ok || !isArray) {
140         ErrorLog("ParseStringVector: not array");
141         return false;
142     }
143     uint32_t arrayLen = 0;
144     napi_get_array_length(env, args, &arrayLen);
145     if (arrayLen > maxLen) {
146         ErrorLog("ParseStringVector, too big array!");
147         return false;
148     }
149     for (uint32_t i = 0; i < arrayLen; i++) {
150         napi_value element = nullptr;
151         napi_get_element(env, args, i, &element);
152 
153         napi_valuetype valueType;
154         napi_typeof(env, element, &valueType);
155         if (valueType != napi_string) {
156             ErrorLog("ParseStringVector, not string!");
157             return false;
158         }
159 
160         std::string stringValue;
161         ParseString(env, stringValue, element);
162         vec.push_back(stringValue);
163     }
164     return true;
165 }
166 
ParseElementName(napi_env &env, ElementName &element, napi_value &args)167 bool ParseElementName(napi_env &env, ElementName &element, napi_value &args)
168 {
169     napi_valuetype valueType = napi_undefined;
170     napi_typeof(env, args, &valueType);
171     if (valueType != napi_object) {
172         ErrorLog("ParseElementName, not object!");
173         return false;
174     }
175     napi_value param = nullptr;
176     napi_get_named_property(env, args, "bundleName", &param);
177     std::string bundleName;
178     ParseString(env, bundleName, param);
179 
180     param = nullptr;
181     napi_get_named_property(env, args, "moduleName", &param);
182     std::string moduleName;
183     ParseString(env, moduleName, param);
184 
185     param = nullptr;
186     napi_get_named_property(env, args, "abilityName", &param);
187     std::string abilityName;
188     ParseString(env, abilityName, param);
189 
190     DebugLog("ParseElementName: bundleName:%{public}s, moduleName:%{public}s, abilityName:%{public}s",
191         bundleName.c_str(), moduleName.c_str(), abilityName.c_str());
192     element.SetBundleName(bundleName);
193     element.SetModuleName(moduleName);
194     element.SetAbilityName(abilityName);
195     return true;
196 }
197 
ParseArrayBuffer(napi_env env, uint8_t **data, size_t &size, napi_value args)198 bool ParseArrayBuffer(napi_env env, uint8_t **data, size_t &size, napi_value args)
199 {
200     napi_status status;
201     napi_valuetype valuetype;
202     napi_typeof(env, args, &valuetype);
203 
204     DebugLog("param=%{public}d.", valuetype);
205     if (valuetype != napi_object) {
206         ErrorLog("Wrong argument type. object expected.");
207         return false;
208     }
209 
210     status = napi_get_arraybuffer_info(env, args, reinterpret_cast<void **>(data), &size);
211     if (status != napi_ok) {
212         ErrorLog("can not get arraybuffer, error is %{public}d", status);
213         (*data)[0] = 0;
214         return false;
215     }
216     DebugLog("arraybuffer size is %{public}zu,buffer is %{public}d", size, (*data)[0]);
217     return true;
218 }
219 
UndefinedNapiValue(const napi_env &env)220 napi_value UndefinedNapiValue(const napi_env &env)
221 {
222     napi_value result;
223     napi_get_undefined(env, &result);
224     return result;
225 }
226 
ConvertStringVector(napi_env env, napi_value jsValue)227 std::vector<std::string> ConvertStringVector(napi_env env, napi_value jsValue)
228 {
229     bool isTypedArray = false;
230     napi_status status = napi_is_typedarray(env, jsValue, &isTypedArray);
231     if (status != napi_ok || !isTypedArray) {
232         ErrorLog("%{public}s called, napi_is_typedarray error", __func__);
233         return {};
234     }
235 
236     napi_typedarray_type type;
237     size_t length = 0;
238     napi_value buffer = nullptr;
239     size_t offset = 0;
240     NAPI_CALL_BASE(env, napi_get_typedarray_info(env, jsValue, &type, &length, nullptr, &buffer, &offset), {});
241     if (type != napi_uint8_array) {
242         ErrorLog("%{public}s called, napi_uint8_array is null", __func__);
243         return {};
244     }
245     std::string *data = nullptr;
246     size_t total = 0;
247     NAPI_CALL_BASE(env, napi_get_arraybuffer_info(env, buffer, reinterpret_cast<void **>(&data), &total), {});
248     length = std::min<size_t>(length, total - offset);
249     std::vector<std::string> result(sizeof(std::string) + length);
250     int retCode = memcpy_s(result.data(), result.size(), &data[offset], length);
251     if (retCode != 0) {
252         return {};
253     }
254     return result;
255 }
256 
CreateErrorMessage(napi_env env, const std::string &msg, int32_t errorCode)257 napi_value CreateErrorMessage(napi_env env, const std::string &msg, int32_t errorCode)
258 {
259     napi_value result = nullptr;
260     napi_value message = nullptr;
261     NAPI_CALL(env, napi_create_string_utf8(env, msg.c_str(), msg.length(), &message));
262     napi_value codeValue = nullptr;
263     std::string errCode = std::to_string(errorCode);
264     NAPI_CALL(env, napi_create_string_utf8(env, errCode.c_str(), errCode.length(), &codeValue));
265     NAPI_CALL(env, napi_create_error(env, codeValue, message, &result));
266     return result;
267 }
268 
CreateUndefined(napi_env env)269 napi_value CreateUndefined(napi_env env)
270 {
271     napi_value result = nullptr;
272     NAPI_CALL(env, napi_get_undefined(env, &result));
273     return result;
274 }
275 
GetNapiStringValue( napi_env env, napi_value napiValue, const std::string &name, const std::string &defValue)276 std::string GetNapiStringValue(
277     napi_env env, napi_value napiValue, const std::string &name, const std::string &defValue)
278 {
279     napi_value value = GetNamedProperty(env, napiValue, name);
280     if (value != nullptr) {
281         return GetStringFromValue(env, value);
282     } else {
283         return defValue;
284     }
285 }
286 
GetStringFromValue(napi_env env, napi_value value)287 std::string GetStringFromValue(napi_env env, napi_value value)
288 {
289     constexpr int32_t maxTextLength = 4096;
290     char msgChars[maxTextLength] = {0};
291     size_t msgLength = 0;
292     NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, value, msgChars, maxTextLength, &msgLength), "");
293     if (msgLength > 0) {
294         return std::string(msgChars, 0, msgLength);
295     } else {
296         return "";
297     }
298 }
299 
GetNamedProperty(napi_env env, napi_value object, const std::string &propertyName)300 napi_value GetNamedProperty(napi_env env, napi_value object, const std::string &propertyName)
301 {
302     napi_value value = nullptr;
303     bool hasProperty = false;
304     NAPI_CALL(env, napi_has_named_property(env, object, propertyName.data(), &hasProperty));
305     if (hasProperty) {
306         NAPI_CALL(env, napi_get_named_property(env, object, propertyName.data(), &value));
307     }
308     return value;
309 }
310 
GetNapiInt32Value(napi_env env, napi_value napiValue, const std::string &name, const int32_t &defValue)311 int32_t GetNapiInt32Value(napi_env env, napi_value napiValue, const std::string &name, const int32_t &defValue)
312 {
313     napi_value value = GetNamedProperty(env, napiValue, name);
314     if (value != nullptr) {
315         int32_t intValue = 0;
316         napi_status getIntStatus = napi_get_value_int32(env, value, &intValue);
317         if (getIntStatus == napi_ok) {
318             return intValue;
319         }
320     }
321     return defValue;
322 }
323 
UnwrapStringFromJS(napi_env env, napi_value param)324 std::string UnwrapStringFromJS(napi_env env, napi_value param)
325 {
326     constexpr size_t maxTextLength = 1024;
327     char msgChars[maxTextLength] = {0};
328     size_t msgLength = 0;
329     NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, param, msgChars, maxTextLength, &msgLength), "");
330     DebugLog("NapiUtil GetStringFromValue msgLength = %{public}zu", msgLength);
331     if (msgLength > 0) {
332         return std::string(msgChars, 0, msgLength);
333     } else {
334         return "";
335     }
336 }
337 
JsStringToBytesVector(napi_env env, napi_value &src, std::vector<unsigned char> &values)338 void JsStringToBytesVector(napi_env env, napi_value &src, std::vector<unsigned char> &values)
339 {
340     napi_valuetype valueType = napi_undefined;
341     napi_typeof(env, src, &valueType);
342     if (valueType != napi_string) {
343         return;
344     }
345 
346     std::string data;
347     ParseString(env, data, src);
348     NfcSdkCommon::HexStringToBytes(data, values);
349 }
350 
ConvertStringVectorToJS(napi_env env, napi_value &result, std::vector<std::string>& stringVector)351 void ConvertStringVectorToJS(napi_env env, napi_value &result, std::vector<std::string>& stringVector)
352 {
353     DebugLog("ConvertStringVectorToJS called");
354     size_t idx = 0;
355 
356     if (stringVector.empty()) {
357         WarnLog("ConvertStringVectorToJS stringVector empty");
358         napi_create_array_with_length(env, 0, &result);
359         return;
360     }
361     DebugLog("ConvertStringVectorToJS size is %{public}zu", stringVector.size());
362     for (auto& str : stringVector) {
363         napi_value obj = nullptr;
364         napi_create_string_utf8(env, str.c_str(), NAPI_AUTO_LENGTH, &obj);
365         napi_set_element(env, result, idx, obj);
366         idx++;
367     }
368 }
369 
BytesVectorToJS(napi_env env, napi_value &result, std::vector<unsigned char>& src)370 void BytesVectorToJS(napi_env env, napi_value &result, std::vector<unsigned char>& src)
371 {
372     if (src.empty()) {
373         WarnLog("BytesVectorToJS src empty");
374         napi_create_array_with_length(env, 0, &result);
375         return;
376     }
377     size_t idx = 0;
378     DebugLog("BytesVectorToJS size is %{public}zu", src.size());
379     napi_create_array_with_length(env, src.size(), &result);
380     for (auto& num : src) {
381         napi_value obj = nullptr;
382         napi_create_uint32(env, num, &obj);
383         napi_set_element(env, result, idx, obj);
384         idx++;
385     }
386 }
387 
ConvertStringToNumberArray(napi_env env, napi_value &result, std::string srcValue)388 void ConvertStringToNumberArray(napi_env env, napi_value &result, std::string srcValue)
389 {
390     if (srcValue.empty()) {
391         WarnLog("ConvertStringToNumberArray srcValue empty");
392         napi_create_array_with_length(env, 0, &result);
393         return;
394     }
395     uint32_t strLength = srcValue.length();
396     if (strLength % HEX_BYTE_LEN != 0) {
397         srcValue = '0' + srcValue;
398         strLength++;
399     }
400 
401     napi_create_array_with_length(env, (strLength / HEX_BYTE_LEN), &result);
402     unsigned int srcIntValue;
403     for (uint32_t i = 0; i < strLength; i += HEX_BYTE_LEN) {
404         // parse the hex string bytes into array.
405         std::string oneByte = srcValue.substr(i, HEX_BYTE_LEN);
406         if (sscanf_s(oneByte.c_str(), "%x", &srcIntValue) <= 0) {
407             ErrorLog("ConvertStringToNumberArray, sscanf_s failed.");
408             return;
409         }
410         unsigned char hexByte = static_cast<unsigned char>(srcIntValue & 0xFF);
411         napi_value hexByteValue = nullptr;
412         napi_create_int32(env, hexByte, &hexByteValue);
413         napi_set_element(env, result, (i / HEX_BYTE_LEN), hexByteValue);
414     }
415 }
416 
IsAirTouch(std::vector<std::shared_ptr<NdefRecord>> &ndefRecords)417 bool IsAirTouch(std::vector<std::shared_ptr<NdefRecord>> &ndefRecords)
418 {
419     std::string airTouchFlag = "616972746F756368"; // "airtouch"
420     std::string::size_type idx;
421     for (auto& ndefRecord : ndefRecords) {
422         idx = ndefRecord->payload_.find(airTouchFlag);
423         if (idx != std::string::npos) {
424             WarnLog("IsAirTouch is airtouch.");
425             return true;
426         }
427     }
428     return false;
429 }
430 
ConvertAirTouchNdefRecordToJS(napi_env env, napi_value &result, std::shared_ptr<NdefRecord> &ndefRecord)431 void ConvertAirTouchNdefRecordToJS(napi_env env, napi_value &result, std::shared_ptr<NdefRecord> &ndefRecord)
432 {
433     napi_create_object(env, &result);
434     if (ndefRecord == nullptr) {
435         WarnLog("ConvertNdefRecordToJS ndefRecord is null.");
436         return;
437     }
438 
439     napi_value tnf;
440     napi_create_int32(env, ndefRecord->tnf_, &tnf);
441     napi_set_named_property(env, result, "tnf", tnf);
442 
443     napi_value rtdType;
444     napi_create_string_utf8(env, ndefRecord->tagRtdType_.c_str(), NAPI_AUTO_LENGTH, &rtdType);
445     napi_set_named_property(env, result, "rtdType", rtdType);
446 
447     napi_value id;
448     napi_create_string_utf8(env, ndefRecord->id_.c_str(), NAPI_AUTO_LENGTH, &id);
449     napi_set_named_property(env, result, "id", id);
450 
451     napi_value payload;
452     napi_create_string_utf8(env, ndefRecord->payload_.c_str(), NAPI_AUTO_LENGTH, &payload);
453     napi_set_named_property(env, result, "payload", payload);
454 }
455 
ConvertNdefRecordVectorToJS(napi_env env, napi_value &result, std::vector<std::shared_ptr<NdefRecord>> &ndefRecords)456 void ConvertNdefRecordVectorToJS(napi_env env, napi_value &result,
457                                  std::vector<std::shared_ptr<NdefRecord>> &ndefRecords)
458 {
459     napi_create_array(env, &result);
460     if (ndefRecords.empty()) {
461         WarnLog("ConvertNdefRecordVectorToJS ndefRecords is empty.");
462         return;
463     }
464     bool isAirtouchFlag = IsAirTouch(ndefRecords);
465     size_t idx = 0;
466     for (auto& ndefRecord : ndefRecords) {
467         napi_value obj = nullptr;
468         if (isAirtouchFlag) {
469             ConvertAirTouchNdefRecordToJS(env, obj, ndefRecord);
470         } else {
471             ConvertNdefRecordToJS(env, obj, ndefRecord);
472         }
473         napi_set_element(env, result, idx, obj);
474         idx++;
475     }
476 }
477 
ConvertNdefRecordToJS(napi_env env, napi_value &result, std::shared_ptr<NdefRecord> &ndefRecord)478 void ConvertNdefRecordToJS(napi_env env, napi_value &result, std::shared_ptr<NdefRecord> &ndefRecord)
479 {
480     napi_create_object(env, &result);
481     if (ndefRecord == nullptr) {
482         WarnLog("ConvertNdefRecordToJS ndefRecord is null.");
483         return;
484     }
485 
486     napi_value tnf;
487     napi_create_int32(env, ndefRecord->tnf_, &tnf);
488     napi_set_named_property(env, result, "tnf", tnf);
489 
490     napi_value rtdType;
491     std::vector<unsigned char> rtdTypeBytes;
492     NfcSdkCommon::HexStringToBytes(ndefRecord->tagRtdType_, rtdTypeBytes);
493     BytesVectorToJS(env, rtdType, rtdTypeBytes);
494     napi_set_named_property(env, result, "rtdType", rtdType);
495 
496     napi_value id;
497     std::vector<unsigned char> idBytes;
498     NfcSdkCommon::HexStringToBytes(ndefRecord->id_, idBytes);
499     BytesVectorToJS(env, id, idBytes);
500     napi_set_named_property(env, result, "id", id);
501 
502     napi_value payload;
503     std::vector<unsigned char> payloadBytes;
504     NfcSdkCommon::HexStringToBytes(ndefRecord->payload_, payloadBytes);
505     BytesVectorToJS(env, payload, payloadBytes);
506     napi_set_named_property(env, result, "payload", payload);
507 }
508 
MatchValueType(napi_env env, napi_value value, napi_valuetype targetType)509 bool MatchValueType(napi_env env, napi_value value, napi_valuetype targetType)
510 {
511     napi_valuetype valueType = napi_undefined;
512     NAPI_CALL_BASE(env, napi_typeof(env, value, &valueType), false);
513     return valueType == targetType;
514 }
515 
MatchParameters(napi_env env, const napi_value parameters[], std::initializer_list<napi_valuetype> valueTypes)516 bool MatchParameters(napi_env env, const napi_value parameters[], std::initializer_list<napi_valuetype> valueTypes)
517 {
518     if (parameters == nullptr) {
519         return false;
520     }
521     int i = 0;
522     for (auto beg = valueTypes.begin(); beg != valueTypes.end(); ++beg) {
523         if (!MatchValueType(env, parameters[i], *beg)) {
524             return false;
525         }
526         ++i;
527     }
528     return true;
529 }
530 
HandleAsyncWork(napi_env env, BaseContext *baseContext, const std::string &workName, napi_async_execute_callback execute, napi_async_complete_callback complete)531 napi_value HandleAsyncWork(napi_env env, BaseContext *baseContext, const std::string &workName,
532     napi_async_execute_callback execute, napi_async_complete_callback complete)
533 {
534     DebugLog("NfcUtil HandleAsyncWork workName = %{public}s", workName.c_str());
535     std::unique_ptr<BaseContext> context(baseContext);
536     if (context == nullptr) {
537         std::string errorCode = std::to_string(napi_invalid_arg);
538         NAPI_CALL(env, napi_throw_error(env, errorCode.c_str(), ERR_INIT_CONTEXT.c_str()));
539     }
540     napi_value result = nullptr;
541     if (context != nullptr && context->callbackRef == nullptr) {
542         NAPI_CALL(env, napi_create_promise(env, &context->deferred, &result));
543     } else {
544         NAPI_CALL(env, napi_get_undefined(env, &result));
545     }
546     napi_value resource = CreateUndefined(env);
547     napi_value resourceName = nullptr;
548     NAPI_CALL(env, napi_create_string_utf8(env, workName.data(), NAPI_AUTO_LENGTH, &resourceName));
549     NAPI_CALL(env,
550         napi_create_async_work(env, resource, resourceName, execute, complete, static_cast<void *>(context.get()),
551             &context->work));
552     napi_status queueWorkStatus = napi_queue_async_work(env, context->work);
553     if (queueWorkStatus == napi_ok) {
554         context.release();
555         DebugLog("NapiUtil HandleAsyncWork napi_queue_async_work ok");
556     } else {
557         std::string errorCode = std::to_string(queueWorkStatus);
558         NAPI_CALL(env, napi_throw_error(env, errorCode.c_str(), ERR_INIT_CONTEXT.c_str()));
559     }
560     DebugLog("NfcUtil HandleAsyncWork end");
561     return result;
562 }
563 
DoAsyncCallbackOrPromise(const napi_env &env, BaseContext *baseContext, napi_value callbackValue)564 void DoAsyncCallbackOrPromise(const napi_env &env, BaseContext *baseContext, napi_value callbackValue)
565 {
566     if (baseContext == nullptr) {
567         ErrorLog("DoAsyncCallbackOrPromise serious error baseContext nullptr");
568         return;
569     }
570     if (baseContext->callbackRef != nullptr) {
571         DebugLog("DoAsyncCallbackOrPromise for callback");
572         napi_value recv = CreateUndefined(env);
573         napi_value callbackFunc = nullptr;
574         NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, baseContext->callbackRef, &callbackFunc));
575         napi_value callbackValues[] = {nullptr, nullptr};
576         callbackValues[0] = baseContext->resolved ? CreateUndefined(env) : callbackValue;
577         callbackValues[1] = baseContext->resolved ? callbackValue : CreateUndefined(env);
578         napi_value result = nullptr;
579         NAPI_CALL_RETURN_VOID(
580             env, napi_call_function(env, recv, callbackFunc, std::size(callbackValues), callbackValues, &result));
581         NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, baseContext->callbackRef));
582     } else if (baseContext->deferred != nullptr) {
583         DebugLog("DoAsyncCallbackOrPromise for promise");
584         if (baseContext->resolved) {
585             NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, baseContext->deferred, callbackValue));
586         } else {
587             NAPI_CALL_RETURN_VOID(env, napi_reject_deferred(env, baseContext->deferred, callbackValue));
588         }
589     }
590     napi_delete_async_work(env, baseContext->work);
591     delete baseContext;
592     baseContext = nullptr;
593 }
594 
ThrowAsyncError(const napi_env &env, BaseContext *baseContext, int errCode, const std::string &errMsg)595 void ThrowAsyncError(const napi_env &env, BaseContext *baseContext, int errCode, const std::string &errMsg)
596 {
597     if (baseContext == nullptr) {
598         ErrorLog("ThrowAsyncError serious error baseContext nullptr");
599         return;
600     }
601     napi_value businessError = CreateErrorMessage(env, errMsg, errCode);
602     if (baseContext->callbackRef != nullptr) {
603         DebugLog("ThrowAsyncError for callback");
604         napi_value recv = CreateUndefined(env);
605         napi_value callbackFunc = nullptr;
606         NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, baseContext->callbackRef, &callbackFunc));
607         napi_value callbackValues[] = {nullptr, nullptr};
608         callbackValues[0] = businessError; // parameter "error"
609         callbackValues[1] = CreateUndefined(env); // parameter "callback"
610         napi_value result = nullptr;
611         NAPI_CALL_RETURN_VOID(
612             env, napi_call_function(env, recv, callbackFunc, std::size(callbackValues), callbackValues, &result));
613         NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, baseContext->callbackRef));
614     } else if (baseContext->deferred != nullptr) {
615         DebugLog("ThrowAsyncError for promise");
616         NAPI_CALL_RETURN_VOID(env, napi_reject_deferred(env, baseContext->deferred, businessError));
617     }
618     if (baseContext->work != nullptr) {
619         napi_delete_async_work(env, baseContext->work);
620     }
621     delete baseContext;
622     baseContext = nullptr;
623 }
624 
IsNumberArray(const napi_env &env, const napi_value &param)625 bool IsNumberArray(const napi_env &env, const napi_value &param)
626 {
627     if (!IsArray(env, param)) {
628         return false;
629     }
630 
631     uint32_t arrayLength = 0;
632     napi_get_array_length(env, param, &arrayLength);
633     napi_value elementValue = nullptr;
634     for (uint32_t i = 0; i < arrayLength; ++i) {
635         napi_get_element(env, param, i, &elementValue);
636         napi_valuetype elementType = napi_undefined;
637         napi_typeof(env, elementValue, &elementType);
638         if (elementType != napi_number) {
639             return false;
640         }
641     }
642     return true;
643 }
644 
IsObjectArray(const napi_env &env, const napi_value &param)645 bool IsObjectArray(const napi_env &env, const napi_value &param)
646 {
647     if (!IsArray(env, param)) {
648         return false;
649     }
650 
651     uint32_t arrayLength = 0;
652     napi_get_array_length(env, param, &arrayLength);
653     napi_value elementValue = nullptr;
654     for (uint32_t i = 0; i < arrayLength; ++i) {
655         napi_get_element(env, param, i, &elementValue);
656         napi_valuetype elementType = napi_undefined;
657         napi_typeof(env, elementValue, &elementType);
658         if (elementType != napi_object) {
659             return false;
660         }
661     }
662     return true;
663 }
664 
IsArray(const napi_env &env, const napi_value &param)665 bool IsArray(const napi_env &env, const napi_value &param)
666 {
667     bool arrayType = false;
668     napi_status status = napi_is_array(env, param, &arrayType);
669     if (status != napi_ok || !arrayType) {
670         return false;
671     }
672 
673     uint32_t arrayLength = 0;
674     napi_get_array_length(env, param, &arrayLength);
675     if (arrayLength == 0) {
676         return false;
677     }
678     return true;
679 }
680 
IsNumber(const napi_env &env, const napi_value &param)681 bool IsNumber(const napi_env &env, const napi_value &param)
682 {
683     napi_valuetype valueType = napi_undefined;
684     napi_typeof(env, param, &valueType);
685     return valueType == napi_number;
686 }
687 
IsString(const napi_env &env, const napi_value &param)688 bool IsString(const napi_env &env, const napi_value &param)
689 {
690     napi_valuetype valueType = napi_undefined;
691     napi_typeof(env, param, &valueType);
692     return valueType == napi_string;
693 }
694 
IsObject(const napi_env &env, const napi_value &param)695 bool IsObject(const napi_env &env, const napi_value &param)
696 {
697     napi_valuetype valueType = napi_undefined;
698     napi_typeof(env, param, &valueType);
699     return valueType == napi_object;
700 }
701 
IsFunction(const napi_env &env, const napi_value &param)702 bool IsFunction(const napi_env &env, const napi_value &param)
703 {
704     napi_valuetype valueType = napi_undefined;
705     napi_typeof(env, param, &valueType);
706     return valueType == napi_function;
707 }
708 
BuildOutputErrorCode(int errCode)709 int BuildOutputErrorCode(int errCode)
710 {
711     if (errCode == BUSI_ERR_PERM) {
712         return BUSI_ERR_PERM;
713     } else if (errCode == BUSI_ERR_PARAM) {
714         return BUSI_ERR_PARAM;
715     } else if (errCode == ERR_TAG_STATE_IO_FAILED) {
716         return BUSI_ERR_IO_OPERATION_INVALID;
717     } else if (errCode >= ERR_TAG_BASE && errCode < ERR_CE_BASE) {
718         return BUSI_ERR_TAG_STATE_INVALID;
719     }
720     return errCode;
721 }
722 
BuildOutputErrorCodeHce(int errCode)723 int BuildOutputErrorCodeHce(int errCode)
724 {
725     if (errCode == BUSI_ERR_PERM) {
726         return BUSI_ERR_PERM;
727     }
728     if (errCode == BUSI_ERR_PARAM) {
729         return BUSI_ERR_PARAM;
730     }
731     if (errCode == BUSI_ERR_NOT_SYSTEM_APP) {
732         return BUSI_ERR_NOT_SYSTEM_APP;
733     }
734     return BUSI_ERR_HCE_STATE_INVALID;
735 }
736 
BuildErrorMessage(int errCode, std::string funcName, std::string forbiddenPerm, std::string paramName, std::string expertedType)737 std::string BuildErrorMessage(int errCode, std::string funcName, std::string forbiddenPerm,
738     std::string paramName, std::string expertedType)
739 {
740     std::string errMsg;
741     if (errCode == BUSI_ERR_PERM) {
742         return errMsg.append("Permission denied. An attempt was made to ${")
743             .append(funcName)
744             .append("} forbidden by permission: ${")
745             .append(forbiddenPerm)
746             .append("}.");
747     } else if (errCode == BUSI_ERR_PARAM) {
748         if (paramName.length() > 0) {
749             return errMsg.append("Parameter error. The type of \"${")
750                 .append(paramName)
751                 .append("}\" must be ${")
752                 .append(expertedType)
753                 .append("}.");
754         } else {
755             return "Parameter error. The parameter number is invalid.";
756         }
757     } else if (errCode == BUSI_ERR_TAG_STATE_INVALID) {
758         return "Tag running state is abnormal in service.";
759     } else if (errCode == BUSI_ERR_ELEMENT_STATE_INVALID) {
760         return "The element state is invalid.";
761     } else if (errCode == BUSI_ERR_REGISTER_STATE_INVALID) {
762         return "The off() can be called only when the on() has been called.";
763     } else if (errCode == BUSI_ERR_HCE_STATE_INVALID) {
764         return "HCE running state is abnormal in service.";
765     } else if (errCode == BUSI_ERR_NOT_SYSTEM_APP) {
766         return "Not system application.";
767     }
768     return "Unknown error message";
769 }
770 
GenerateBusinessError(const napi_env &env, int errCode, const std::string &errMessage)771 napi_value GenerateBusinessError(const napi_env &env, int errCode, const std::string &errMessage)
772 {
773     napi_value code = nullptr;
774     napi_create_uint32(env, errCode, &code);
775     napi_value message = nullptr;
776     napi_create_string_utf8(env, errMessage.c_str(), NAPI_AUTO_LENGTH, &message);
777     napi_value businessError = nullptr;
778     napi_create_error(env, nullptr, message, &businessError);
779     napi_set_named_property(env, businessError, KEY_CODE.c_str(), code);
780     return businessError;
781 }
782 
CheckUnwrapStatusAndThrow(const napi_env &env, napi_status status, int errCode)783 bool CheckUnwrapStatusAndThrow(const napi_env &env, napi_status status, int errCode)
784 {
785     if (status != napi_ok) {
786         napi_throw(env, GenerateBusinessError(env, errCode, BuildErrorMessage(errCode, "", "", "", "")));
787         return false;
788     }
789     return true;
790 }
CheckContextAndThrow(const napi_env &env, const BaseContext *context, int errCode)791 bool CheckContextAndThrow(const napi_env &env, const BaseContext *context, int errCode)
792 {
793     if (context == nullptr) {
794         napi_throw(env, GenerateBusinessError(env, errCode, BuildErrorMessage(errCode, "", "", "", "")));
795         return false;
796     }
797     return true;
798 }
CheckParametersAndThrow(const napi_env &env, const napi_value parameters[], std::initializer_list<napi_valuetype> types, const std::string &argName, const std::string &argType)799 bool CheckParametersAndThrow(const napi_env &env, const napi_value parameters[],
800     std::initializer_list<napi_valuetype> types, const std::string &argName, const std::string &argType)
801 {
802     if (!MatchParameters(env, parameters, types)) {
803         napi_throw(env, GenerateBusinessError(env, BUSI_ERR_PARAM, BuildErrorMessage(BUSI_ERR_PARAM,
804             "", "", argName, argType)));
805         return false;
806     }
807     return true;
808 }
CheckArrayNumberAndThrow(const napi_env &env, const napi_value &param, const std::string &argName, const std::string &argType)809 bool CheckArrayNumberAndThrow(const napi_env &env, const napi_value &param, const std::string &argName,
810     const std::string &argType)
811 {
812     if (!IsNumberArray(env, param)) {
813         napi_throw(env, GenerateBusinessError(env, BUSI_ERR_PARAM, BuildErrorMessage(BUSI_ERR_PARAM,
814             "", "", argName, argType)));
815         return false;
816     }
817     return true;
818 }
CheckNumberAndThrow(const napi_env &env, const napi_value &param, const std::string &argName, const std::string &argType)819 bool CheckNumberAndThrow(const napi_env &env, const napi_value &param, const std::string &argName,
820     const std::string &argType)
821 {
822     if (!IsNumber(env, param)) {
823         napi_throw(env, GenerateBusinessError(env, BUSI_ERR_PARAM, BuildErrorMessage(BUSI_ERR_PARAM,
824             "", "", argName, argType)));
825         return false;
826     }
827     return true;
828 }
CheckStringAndThrow(const napi_env &env, const napi_value &param, const std::string &argName, const std::string &argType)829 bool CheckStringAndThrow(const napi_env &env, const napi_value &param, const std::string &argName,
830     const std::string &argType)
831 {
832     if (!IsString(env, param)) {
833         napi_throw(env, GenerateBusinessError(env, BUSI_ERR_PARAM, BuildErrorMessage(BUSI_ERR_PARAM,
834             "", "", argName, argType)));
835         return false;
836     }
837     return true;
838 }
CheckObjectAndThrow(const napi_env &env, const napi_value &param, const std::string &argName, const std::string &argType)839 bool CheckObjectAndThrow(const napi_env &env, const napi_value &param, const std::string &argName,
840     const std::string &argType)
841 {
842     if (!IsObject(env, param)) {
843         napi_throw(env, GenerateBusinessError(env, BUSI_ERR_PARAM, BuildErrorMessage(BUSI_ERR_PARAM,
844             "", "", argName, argType)));
845         return false;
846     }
847     return true;
848 }
849 
CheckFunctionAndThrow(const napi_env &env, const napi_value &param, const std::string &argName, const std::string &argType)850 bool CheckFunctionAndThrow(const napi_env &env, const napi_value &param, const std::string &argName,
851     const std::string &argType)
852 {
853     if (!IsFunction(env, param)) {
854         napi_throw(env, GenerateBusinessError(env, BUSI_ERR_PARAM, BuildErrorMessage(BUSI_ERR_PARAM,
855             "", "", argName, argType)));
856         return false;
857     }
858     return true;
859 }
860 
CheckArgCountAndThrow(const napi_env &env, int argCount, int expCount)861 bool CheckArgCountAndThrow(const napi_env &env, int argCount, int expCount)
862 {
863     if (argCount != expCount) {
864         napi_throw(env, GenerateBusinessError(env, BUSI_ERR_PARAM, BuildErrorMessage(BUSI_ERR_PARAM,
865             "", "", "", "")));
866         return false;
867     }
868     return true;
869 }
CheckTagStatusCodeAndThrow(const napi_env &env, int statusCode, const std::string &funcName)870 bool CheckTagStatusCodeAndThrow(const napi_env &env, int statusCode, const std::string &funcName)
871 {
872     if (statusCode == BUSI_ERR_PERM) {
873         napi_throw(env, GenerateBusinessError(env, BUSI_ERR_PERM,
874             BuildErrorMessage(BUSI_ERR_PERM, funcName, TAG_PERM_DESC, "", "")));
875         return false;
876     } else if (statusCode == ERR_TAG_STATE_IO_FAILED) {
877         napi_throw(env, GenerateBusinessError(env, ERR_TAG_STATE_IO_FAILED,
878             BuildErrorMessage(BUSI_ERR_IO_OPERATION_INVALID, funcName, "", "", "")));
879         return false;
880     } else if (statusCode >= ErrorCode::ERR_TAG_PARAMETERS && statusCode < ErrorCode::ERR_CE_BASE) {
881         napi_throw(env, GenerateBusinessError(env, BUSI_ERR_TAG_STATE_INVALID,
882             BuildErrorMessage(BUSI_ERR_TAG_STATE_INVALID, "", "", "", "")));
883         return false;
884     }
885     return true;
886 }
887 
CheckHceStatusCodeAndThrow(const napi_env &env, int statusCode, const std::string &funcName)888 bool CheckHceStatusCodeAndThrow(const napi_env &env, int statusCode, const std::string &funcName)
889 {
890     if (statusCode == KITS::ERR_NONE) {
891         return true;
892     }
893     if (statusCode == BUSI_ERR_NOT_SYSTEM_APP) {
894         napi_throw(env, GenerateBusinessError(env, BUSI_ERR_NOT_SYSTEM_APP,
895                                               BuildErrorMessage(BUSI_ERR_NOT_SYSTEM_APP, funcName, "", "", "")));
896         return false;
897     }
898     if (statusCode == BUSI_ERR_PERM) {
899         napi_value busErr = GenerateBusinessError(
900             env, BUSI_ERR_PERM, BuildErrorMessage(BUSI_ERR_PERM, funcName, CARD_EMULATION_PERM_DESC, "", ""));
901         napi_throw(env, busErr);
902         return false;
903     }
904 
905     napi_throw(env, GenerateBusinessError(env, BUSI_ERR_HCE_STATE_INVALID,
906                                           BuildErrorMessage(BUSI_ERR_HCE_STATE_INVALID, "", "", "", "")));
907     return false;
908 }
909 } // namespace KITS
910 } // namespace NFC
911 } // namespace OHOS
912