1 /*
2  * Copyright (c) 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_scan_utils.h"
17 
18 #include <fcntl.h>
19 #include "ability.h"
20 #include "napi_base_context.h"
21 #include "scan_log.h"
22 #include "scan_util.h"
23 #include "securec.h"
24 
25 namespace OHOS::Scan {
26 static constexpr const int MAX_STRING_LENGTH = 65536;
27 const std::string GLOBAL_ID_DELIMITER = ":";
28 const std::string EXTENSION_CID_DELIMITER = ":";
29 const std::string TASK_EVENT_DELIMITER = "-";
30 
GetValueType(napi_env env,napi_value value)31 napi_valuetype NapiScanUtils::GetValueType(napi_env env, napi_value value)
32 {
33     if (value == nullptr) {
34         return napi_undefined;
35     }
36 
37     napi_valuetype valueType = napi_undefined;
38     SCAN_CALL_BASE(env, napi_typeof(env, value, &valueType), napi_undefined);
39     return valueType;
40 }
41 
42 /* named property */
HasNamedProperty(napi_env env,napi_value object,const std::string & propertyName)43 bool NapiScanUtils::HasNamedProperty(napi_env env, napi_value object, const std::string &propertyName)
44 {
45     bool hasProperty = false;
46     SCAN_CALL_BASE(env, napi_has_named_property(env, object, propertyName.c_str(), &hasProperty), false);
47     return hasProperty;
48 }
49 
GetNamedProperty(napi_env env,napi_value object,const std::string & propertyName)50 napi_value NapiScanUtils::GetNamedProperty(napi_env env, napi_value object, const std::string &propertyName)
51 {
52     napi_value value = nullptr;
53     bool hasProperty = false;
54     SCAN_CALL(env, napi_has_named_property(env, object, propertyName.c_str(), &hasProperty));
55     if (!hasProperty) {
56         return value;
57     }
58     SCAN_CALL(env, napi_get_named_property(env, object, propertyName.c_str(), &value));
59     return value;
60 }
61 
SetNamedProperty(napi_env env,napi_value object,const std::string & name,napi_value value)62 void NapiScanUtils::SetNamedProperty(napi_env env, napi_value object, const std::string &name, napi_value value)
63 {
64     (void)napi_set_named_property(env, object, name.c_str(), value);
65 }
66 
GetPropertyNames(napi_env env,napi_value object)67 std::vector<std::string> NapiScanUtils::GetPropertyNames(napi_env env, napi_value object)
68 {
69     std::vector<std::string> ret;
70     napi_value names = nullptr;
71     SCAN_CALL_BASE(env, napi_get_property_names(env, object, &names), ret);
72     uint32_t length = 0;
73     SCAN_CALL_BASE(env, napi_get_array_length(env, names, &length), ret);
74     for (uint32_t index = 0; index < length; ++index) {
75         napi_value name = nullptr;
76         if (napi_get_element(env, names, index, &name) != napi_ok) {
77             continue;
78         }
79         if (GetValueType(env, name) != napi_string) {
80             continue;
81         }
82         ret.emplace_back(GetStringFromValueUtf8(env, name));
83     }
84     return ret;
85 }
86 
87 /* UINT32 */
CreateUint32(napi_env env,uint32_t code)88 napi_value NapiScanUtils::CreateUint32(napi_env env, uint32_t code)
89 {
90     napi_value value = nullptr;
91     if (napi_create_uint32(env, code, &value) != napi_ok) {
92         return nullptr;
93     }
94     return value;
95 }
96 
GetUint32FromValue(napi_env env,napi_value value)97 uint32_t NapiScanUtils::GetUint32FromValue(napi_env env, napi_value value)
98 {
99     uint32_t ret = 0;
100     SCAN_CALL_BASE(env, napi_get_value_uint32(env, value, &ret), 0);
101     return ret;
102 }
103 
GetUint32Property(napi_env env,napi_value object,const std::string & propertyName)104 uint32_t NapiScanUtils::GetUint32Property(napi_env env, napi_value object, const std::string &propertyName)
105 {
106     if (!HasNamedProperty(env, object, propertyName)) {
107         return 0;
108     }
109     napi_value value = GetNamedProperty(env, object, propertyName);
110     return GetUint32FromValue(env, value);
111 }
112 
SetUint32Property(napi_env env,napi_value object,const std::string & name,uint32_t value)113 void NapiScanUtils::SetUint32Property(napi_env env, napi_value object, const std::string &name, uint32_t value)
114 {
115     napi_value jsValue = CreateUint32(env, value);
116     if (GetValueType(env, jsValue) != napi_number) {
117         return;
118     }
119 
120     napi_set_named_property(env, object, name.c_str(), jsValue);
121 }
122 
123 /* INT32 */
CreateInt32(napi_env env,int32_t code)124 napi_value NapiScanUtils::CreateInt32(napi_env env, int32_t code)
125 {
126     napi_value value = nullptr;
127     if (napi_create_int32(env, code, &value) != napi_ok) {
128         return nullptr;
129     }
130     return value;
131 }
132 
GetInt32FromValue(napi_env env,napi_value value)133 int32_t NapiScanUtils::GetInt32FromValue(napi_env env, napi_value value)
134 {
135     int32_t ret = 0;
136     SCAN_CALL_BASE(env, napi_get_value_int32(env, value, &ret), 0);
137     return ret;
138 }
139 
GetInt32Property(napi_env env,napi_value object,const std::string & propertyName)140 int32_t NapiScanUtils::GetInt32Property(napi_env env, napi_value object, const std::string &propertyName)
141 {
142     if (!HasNamedProperty(env, object, propertyName)) {
143         return 0;
144     }
145     napi_value value = GetNamedProperty(env, object, propertyName);
146     return GetInt32FromValue(env, value);
147 }
148 
SetInt32Property(napi_env env,napi_value object,const std::string & name,int32_t value)149 void NapiScanUtils::SetInt32Property(napi_env env, napi_value object, const std::string &name, int32_t value)
150 {
151     napi_value jsValue = CreateInt32(env, value);
152     if (GetValueType(env, jsValue) != napi_number) {
153         return;
154     }
155 
156     napi_set_named_property(env, object, name.c_str(), jsValue);
157 }
158 
159 /* String UTF8 */
CreateStringUtf8(napi_env env,const std::string & str)160 napi_value NapiScanUtils::CreateStringUtf8(napi_env env, const std::string &str)
161 {
162     napi_value value = nullptr;
163     if (napi_create_string_utf8(env, str.c_str(), strlen(str.c_str()), &value) != napi_ok) {
164         return nullptr;
165     }
166     return value;
167 }
168 
GetStringFromValueUtf8(napi_env env,napi_value value)169 std::string NapiScanUtils::GetStringFromValueUtf8(napi_env env, napi_value value)
170 {
171     std::string result;
172     std::vector<char> str(MAX_STRING_LENGTH + 1, '\0');
173     size_t length = 0;
174     SCAN_CALL_BASE(env, napi_get_value_string_utf8(env, value, &str[0], MAX_STRING_LENGTH, &length), result);
175     if (length > 0) {
176         return result.append(&str[0], length);
177     }
178     return result;
179 }
180 
GetStringPropertyUtf8(napi_env env,napi_value object,const std::string & propertyName)181 std::string NapiScanUtils::GetStringPropertyUtf8(napi_env env, napi_value object, const std::string &propertyName)
182 {
183     if (!HasNamedProperty(env, object, propertyName)) {
184         return "";
185     }
186     napi_value value = GetNamedProperty(env, object, propertyName);
187     return GetStringFromValueUtf8(env, value);
188 }
189 
SetStringPropertyUtf8(napi_env env,napi_value object,const std::string & name,const std::string & value)190 void NapiScanUtils::SetStringPropertyUtf8(
191     napi_env env, napi_value object, const std::string &name, const std::string &value)
192 {
193     napi_value jsValue = CreateStringUtf8(env, value);
194     if (GetValueType(env, jsValue) != napi_string) {
195         return;
196     }
197     napi_set_named_property(env, object, name.c_str(), jsValue);
198 }
199 
200 /* array buffer */
201 
CreateArrayBuffer(napi_env env,size_t length,void ** data)202 napi_value NapiScanUtils::CreateArrayBuffer(napi_env env, size_t length, void **data)
203 {
204     napi_value object = nullptr;
205     SCAN_CALL(env, napi_create_arraybuffer(env, length, data, &object));
206     return object;
207 }
208 
ValueIsArrayBuffer(napi_env env,napi_value value)209 bool NapiScanUtils::ValueIsArrayBuffer(napi_env env, napi_value value)
210 {
211     bool isArrayBuffer = false;
212     SCAN_CALL_BASE(env, napi_is_arraybuffer(env, value, &isArrayBuffer), false);
213     return isArrayBuffer;
214 }
215 
GetInfoFromArrayBufferValue(napi_env env,napi_value value,size_t * length)216 void *NapiScanUtils::GetInfoFromArrayBufferValue(napi_env env, napi_value value, size_t *length)
217 {
218     if (length == nullptr) {
219         return nullptr;
220     }
221 
222     void *data = nullptr;
223     SCAN_CALL(env, napi_get_arraybuffer_info(env, value, &data, length));
224     return data;
225 }
226 
227 /* object */
CreateObject(napi_env env)228 napi_value NapiScanUtils::CreateObject(napi_env env)
229 {
230     napi_value object = nullptr;
231     SCAN_CALL(env, napi_create_object(env, &object));
232     return object;
233 }
234 
235 /* undefined */
GetUndefined(napi_env env)236 napi_value NapiScanUtils::GetUndefined(napi_env env)
237 {
238     napi_value undefined = nullptr;
239     SCAN_CALL(env, napi_get_undefined(env, &undefined));
240     return undefined;
241 }
242 
243 /* function */
CallFunction(napi_env env,napi_value recv,napi_value func,size_t argc,const napi_value * argv)244 napi_value NapiScanUtils::CallFunction(
245     napi_env env, napi_value recv, napi_value func, size_t argc, const napi_value *argv)
246 {
247     napi_value res = nullptr;
248     SCAN_CALL(env, napi_call_function(env, recv, func, argc, argv, &res));
249     return res;
250 }
251 
252 /* reference */
CreateReference(napi_env env,napi_value callback)253 napi_ref NapiScanUtils::CreateReference(napi_env env, napi_value callback)
254 {
255     napi_ref callbackRef = nullptr;
256     SCAN_CALL(env, napi_create_reference(env, callback, 1, &callbackRef));
257     return callbackRef;
258 }
259 
GetReference(napi_env env,napi_ref callbackRef)260 napi_value NapiScanUtils::GetReference(napi_env env, napi_ref callbackRef)
261 {
262     napi_value callback = nullptr;
263     SCAN_CALL(env, napi_get_reference_value(env, callbackRef, &callback));
264     return callback;
265 }
266 
DeleteReference(napi_env env,napi_ref callbackRef)267 void NapiScanUtils::DeleteReference(napi_env env, napi_ref callbackRef)
268 {
269     if (env != nullptr && callbackRef != nullptr) {
270         (void)napi_delete_reference(env, callbackRef);
271     }
272 }
273 
274 /* boolean */
CreateBoolean(napi_env env,bool value)275 napi_value NapiScanUtils::CreateBoolean(napi_env env, bool value)
276 {
277     napi_value jsValue = nullptr;
278     if (napi_get_boolean(env, value, &jsValue) != napi_ok) {
279         return nullptr;
280     }
281     return jsValue;
282 }
283 
GetBooleanFromValue(napi_env env,napi_value value)284 bool NapiScanUtils::GetBooleanFromValue(napi_env env, napi_value value)
285 {
286     bool ret = false;
287     SCAN_CALL_BASE(env, napi_get_value_bool(env, value, &ret), 0);
288     return ret;
289 }
290 
GetBooleanProperty(napi_env env,napi_value object,const std::string & propertyName)291 bool NapiScanUtils::GetBooleanProperty(napi_env env, napi_value object, const std::string &propertyName)
292 {
293     if (!HasNamedProperty(env, object, propertyName)) {
294         return false;
295     }
296     napi_value value = GetNamedProperty(env, object, propertyName);
297     bool ret = false;
298     SCAN_CALL_BASE(env, napi_get_value_bool(env, value, &ret), false);
299     return ret;
300 }
301 
SetBooleanProperty(napi_env env,napi_value object,const std::string & name,bool value)302 void NapiScanUtils::SetBooleanProperty(napi_env env, napi_value object, const std::string &name, bool value)
303 {
304     napi_value jsValue = nullptr;
305     SCAN_CALL_RETURN_VOID(env, napi_get_boolean(env, value, &jsValue));
306     if (GetValueType(env, jsValue) != napi_boolean) {
307         return;
308     }
309 
310     napi_set_named_property(env, object, name.c_str(), jsValue);
311 }
312 
313 /* define properties */
DefineProperties(napi_env env,napi_value object,const std::initializer_list<napi_property_descriptor> & properties)314 void NapiScanUtils::DefineProperties(
315     napi_env env, napi_value object, const std::initializer_list<napi_property_descriptor> &properties)
316 {
317     napi_property_descriptor descriptors[properties.size()];
318     std::copy(properties.begin(), properties.end(), descriptors);
319 
320     (void)napi_define_properties(env, object, properties.size(), descriptors);
321 }
322 
ToLower(const std::string & s)323 std::string NapiScanUtils::ToLower(const std::string &s)
324 {
325     std::string res = s;
326     std::transform(res.begin(), res.end(), res.begin(), tolower);
327     return res;
328 }
329 
GetValueString(napi_env env,napi_value value)330 std::string NapiScanUtils::GetValueString(napi_env env, napi_value value)
331 {
332     std::string resultValue = "";
333     char value_string[256] = { 0 };
334     size_t value_size = 256;
335     size_t result = 0;
336     napi_status status = napi_get_value_string_utf8(env, value, value_string, value_size, &result);
337     if (status == napi_ok && result > 0) {
338         resultValue = value_string;
339     }
340     return resultValue;
341 }
342 
GetExtensionId(const std::string & globalId)343 std::string NapiScanUtils::GetExtensionId(const std::string &globalId)
344 {
345     auto pos = globalId.find(GLOBAL_ID_DELIMITER);
346     if (pos == std::string::npos) {
347         return "";
348     }
349     return globalId.substr(0, pos);
350 }
351 
GetGlobalId(const std::string & extensionId,const std::string & localId)352 std::string NapiScanUtils::GetGlobalId(const std::string& extensionId, const std::string& localId)
353 {
354     return extensionId + GLOBAL_ID_DELIMITER + localId;
355 }
356 
GetLocalId(const std::string & globalId,const std::string & extensionId)357 std::string NapiScanUtils::GetLocalId(const std::string& globalId, const std::string& extensionId)
358 {
359     auto pos = globalId.find(GLOBAL_ID_DELIMITER);
360     if (pos == std::string::npos) {
361         return "";
362     }
363 
364     if (globalId.substr(0, pos) != extensionId) {
365         return "";
366     }
367     return globalId.substr(pos + 1);
368 }
369 
EncodeExtensionCid(const std::string & extensionId,uint32_t callbackId)370 std::string NapiScanUtils::EncodeExtensionCid(const std::string &extensionId, uint32_t callbackId)
371 {
372     return extensionId + EXTENSION_CID_DELIMITER + std::to_string(callbackId);
373 }
374 
DecodeExtensionCid(const std::string & cid,std::string & extensionId,uint32_t & callbackId)375 bool NapiScanUtils::DecodeExtensionCid(const std::string &cid, std::string &extensionId, uint32_t &callbackId)
376 {
377     auto pos = cid.find(EXTENSION_CID_DELIMITER);
378     if (pos == std::string::npos) {
379         return false;
380     }
381     extensionId = cid.substr(0, pos);
382     int32_t callbackIdTmp = 0;
383     if (!ScanUtil::ConvertToInt(cid.substr(pos + 1), callbackIdTmp)) {
384         return false;
385     }
386     callbackId = static_cast<uint32_t>(callbackIdTmp);
387     return true;
388 }
389 
GetTaskEventId(const std::string & taskId,const std::string & type)390 std::string NapiScanUtils::GetTaskEventId(const std::string &taskId, const std::string &type)
391 {
392     return type + TASK_EVENT_DELIMITER + taskId;
393 }
394 
OpenFile(const std::string & filePath)395 int32_t NapiScanUtils::OpenFile(const std::string &filePath)
396 {
397     if (!IsPathValid(filePath)) {
398         return SCAN_INVALID_ID;
399     }
400     int32_t fd = open(filePath.c_str(), O_RDONLY);
401     SCAN_HILOGD("fd: %{public}d", fd);
402     if (fd < 0) {
403         SCAN_HILOGE("Failed to open file errno: %{public}s", std::to_string(errno).c_str());
404         return SCAN_INVALID_ID;
405     }
406     return fd;
407 }
408 
IsPathValid(const std::string & filePath)409 bool NapiScanUtils::IsPathValid(const std::string &filePath)
410 {
411     auto path = filePath.substr(0, filePath.rfind('/'));
412     char resolvedPath[PATH_MAX + 1] = { 0 };
413     if (path.length() > PATH_MAX || realpath(path.c_str(), resolvedPath) == nullptr ||
414         strncmp(resolvedPath, path.c_str(), path.length()) != 0) {
415         SCAN_HILOGE("invalid file path!");
416         return false;
417     }
418     return true;
419 }
420 
GetIdFromFdPath(const std::string & fdPath)421 uint32_t NapiScanUtils::GetIdFromFdPath(const std::string &fdPath)
422 {
423     std::string fd_str = fdPath.substr(fdPath.rfind('/') + 1, fdPath.length());
424     std::stringstream getStrStream(fd_str);
425     uint32_t fd = 0;
426     if (!(getStrStream >> fd)) {
427         SCAN_HILOGD("failed to convert to uint32");
428     }
429     return fd;
430 }
431 
GetJsVal(napi_env env,napi_callback_info info,napi_value argv[],size_t length)432 size_t NapiScanUtils::GetJsVal(napi_env env, napi_callback_info info, napi_value argv[], size_t length)
433 {
434     size_t argc = length;
435     napi_value thisVal = nullptr;
436     void *data = nullptr;
437     napi_get_cb_info(env, info, &argc, argv, &thisVal, &data);
438     return argc;
439 }
440 
441 } // namespace OHOS::Scan
442