1 /*
2  * Copyright (c) 2021 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 #define LOG_TAG "JSUtils"
16 
17 #include "js_utils.h"
18 
19 #include <cstring>
20 
21 #include "js_native_api_types.h"
22 #include "logger.h"
23 #include "securec.h"
24 using namespace OHOS::Rdb;
25 
26 #define CHECK_RETURN_RET(assertion, message, revt)                   \
27     do {                                                             \
28         if (!(assertion)) {                                          \
29             LOG_WARN("assertion (" #assertion ") failed: " message); \
30             return revt;                                             \
31         }                                                            \
32     } while (0)
33 
34 namespace OHOS {
35 namespace AppDataMgrJsKit {
36 namespace JSUtils {
37     static int32_t g_hapVersion = -1;  // the current apiVersion of hap
38 }
39 
40 static constexpr JSUtils::JsFeatureSpace FEATURE_NAME_SPACES[] = {
41     { "ohos.data.cloudData", "ZGF0YS5jbG91ZERhdGE=", true },
42     { "ohos.data.dataAbility", "ZGF0YS5kYXRhQWJpbGl0eQ==", true },
43     { "ohos.data.dataShare", "ZGF0YS5kYXRhU2hhcmU=", false },
44     { "ohos.data.distributedDataObject", "ZGF0YS5kaXN0cmlidXRlZERhdGFPYmplY3Q=", false },
45     { "ohos.data.distributedKVStore", "ZGF0YS5kaXN0cmlidXRlZEtWU3RvcmU=", false },
46     { "ohos.data.rdb", "ZGF0YS5yZGI=", true },
47     { "ohos.data.relationalStore", "ZGF0YS5yZWxhdGlvbmFsU3RvcmU=", true },
48 };
49 
SetHapVersion(int32_t hapversion)50 void JSUtils::SetHapVersion(int32_t hapversion)
51 {
52     g_hapVersion = hapversion;
53 }
54 
GetHapVersion()55 int32_t JSUtils::GetHapVersion()
56 {
57     return g_hapVersion;
58 }
59 
GetJsFeatureSpace(const std::string & name)60 const std::optional<JSUtils::JsFeatureSpace> JSUtils::GetJsFeatureSpace(const std::string &name)
61 {
62     auto jsFeature = JsFeatureSpace{ name.data(), nullptr, false };
63     auto iter = std::lower_bound(FEATURE_NAME_SPACES,
64         FEATURE_NAME_SPACES + sizeof(FEATURE_NAME_SPACES) / sizeof(FEATURE_NAME_SPACES[0]), jsFeature,
65         [](const JsFeatureSpace &JsFeatureSpace1, const JsFeatureSpace &JsFeatureSpace2) {
66             return strcmp(JsFeatureSpace1.spaceName, JsFeatureSpace2.spaceName) < 0;
67         });
68     if (iter < FEATURE_NAME_SPACES + sizeof(FEATURE_NAME_SPACES) / sizeof(FEATURE_NAME_SPACES[0]) &&
69         strcmp(iter->spaceName, name.data()) == 0) {
70         return *iter;
71     }
72     return std::nullopt;
73 }
74 
GetInnerValue(napi_env env,napi_value in,const std::string & prop,bool optional)75 std::pair<napi_status, napi_value> JSUtils::GetInnerValue(
76     napi_env env, napi_value in, const std::string &prop, bool optional)
77 {
78     bool hasProp = false;
79     napi_status status = napi_has_named_property(env, in, prop.c_str(), &hasProp);
80     if (status != napi_ok) {
81         return std::make_pair(napi_generic_failure, nullptr);
82     }
83     if (!hasProp) {
84         status = optional ? napi_ok : napi_generic_failure;
85         return std::make_pair(status, nullptr);
86     }
87     napi_value inner = nullptr;
88     status = napi_get_named_property(env, in, prop.c_str(), &inner);
89     if (status != napi_ok || inner == nullptr) {
90         return std::make_pair(napi_generic_failure, nullptr);
91     }
92     if (optional && JSUtils::IsNull(env, inner)) {
93         return std::make_pair(napi_ok, nullptr);
94     }
95     return std::make_pair(napi_ok, inner);
96 }
97 
Convert2String(napi_env env,napi_value jsStr)98 std::string JSUtils::Convert2String(napi_env env, napi_value jsStr)
99 {
100     std::string value = ""; // TD: need to check everywhere in use whether empty is work well.
101     JSUtils::Convert2Value(env, jsStr, value);
102     return value;
103 }
104 
Convert2ValueExt(napi_env env,napi_value jsValue,uint32_t & output)105 int32_t JSUtils::Convert2ValueExt(napi_env env, napi_value jsValue, uint32_t &output)
106 {
107     napi_valuetype type = napi_undefined;
108     napi_status status = napi_typeof(env, jsValue, &type);
109     if (status != napi_ok || type != napi_number) {
110         LOG_DEBUG("napi_typeof failed status = %{public}d type = %{public}d", status, type);
111         return napi_invalid_arg;
112     }
113 
114     status = napi_get_value_uint32(env, jsValue, &output);
115     if (status != napi_ok) {
116         LOG_DEBUG("napi_get_value_uint32 failed, status = %{public}d", status);
117         return status;
118     }
119     return status;
120 }
121 
Convert2ValueExt(napi_env env,napi_value jsValue,int32_t & output)122 int32_t JSUtils::Convert2ValueExt(napi_env env, napi_value jsValue, int32_t &output)
123 {
124     napi_valuetype type = napi_undefined;
125     napi_status status = napi_typeof(env, jsValue, &type);
126     if (status != napi_ok || type != napi_number) {
127         LOG_DEBUG("napi_typeof failed status = %{public}d type = %{public}d", status, type);
128         return napi_invalid_arg;
129     }
130 
131     status = napi_get_value_int32(env, jsValue, &output);
132     if (status != napi_ok) {
133         LOG_DEBUG("napi_get_value_int32 failed, status = %{public}d", status);
134         return status;
135     }
136     return status;
137 }
138 
Convert2Value(napi_env env,napi_value jsValue,napi_value & output)139 int32_t JSUtils::Convert2Value(napi_env env, napi_value jsValue, napi_value &output)
140 {
141     output = jsValue;
142     return napi_ok;
143 }
144 
Convert2Value(napi_env env,napi_value jsValue,bool & output)145 int32_t JSUtils::Convert2Value(napi_env env, napi_value jsValue, bool &output)
146 {
147     napi_valuetype type = napi_undefined;
148     napi_status status = napi_typeof(env, jsValue, &type);
149     if (status != napi_ok || type != napi_boolean) {
150         LOG_DEBUG("napi_typeof failed status = %{public}d type = %{public}d", status, type);
151         return napi_invalid_arg;
152     }
153 
154     bool bValue = false;
155     status = napi_get_value_bool(env, jsValue, &bValue);
156     if (status != napi_ok) {
157         LOG_ERROR("napi_get_value_bool failed, status = %{public}d", status);
158         return status;
159     }
160     output = bValue;
161     return status;
162 }
163 
Convert2ValueExt(napi_env env,napi_value jsValue,int64_t & output)164 int32_t JSUtils::Convert2ValueExt(napi_env env, napi_value jsValue, int64_t &output)
165 {
166     napi_valuetype type = napi_undefined;
167     napi_status status = napi_typeof(env, jsValue, &type);
168     if (status != napi_ok || type != napi_number) {
169         LOG_DEBUG("napi_typeof failed status = %{public}d type = %{public}d", status, type);
170         return napi_invalid_arg;
171     }
172 
173     status = napi_get_value_int64(env, jsValue, &output);
174     if (status != napi_ok) {
175         LOG_DEBUG("napi_get_value_int64 failed, status = %{public}d", status);
176         return status;
177     }
178     return status;
179 }
180 
Convert2Value(napi_env env,napi_value jsValue,double & output)181 int32_t JSUtils::Convert2Value(napi_env env, napi_value jsValue, double &output)
182 {
183     napi_valuetype type = napi_undefined;
184     napi_status status = napi_typeof(env, jsValue, &type);
185     if (status != napi_ok || type != napi_number) {
186         LOG_DEBUG("napi_typeof failed status = %{public}d type = %{public}d", status, type);
187         return napi_invalid_arg;
188     }
189 
190     double number = 0.0;
191     status = napi_get_value_double(env, jsValue, &number);
192     if (status != napi_ok) {
193         LOG_DEBUG("napi_get_value_double failed, status = %{public}d", status);
194         return status;
195     }
196     output = number;
197     return status;
198 }
199 
Convert2Value(napi_env env,napi_value jsValue,int64_t & output)200 int32_t JSUtils::Convert2Value(napi_env env, napi_value jsValue, int64_t &output)
201 {
202     return napi_invalid_arg;
203 }
204 
Convert2Value(napi_env env,napi_value jsValue,std::vector<float> & output)205 int32_t JSUtils::Convert2Value(napi_env env, napi_value jsValue, std::vector<float> &output)
206 {
207     bool isTypedArray = false;
208     napi_is_typedarray(env, jsValue, &isTypedArray);
209     if (!isTypedArray) {
210         return napi_invalid_arg;
211     }
212 
213     napi_typedarray_type type;
214     napi_value input_buffer = nullptr;
215     size_t byte_offset = 0;
216     size_t length = 0;
217     void *tmp = nullptr;
218     auto status = napi_get_typedarray_info(env, jsValue, &type, &length, &tmp, &input_buffer, &byte_offset);
219     if (status != napi_ok || type != napi_float32_array) {
220         return napi_invalid_arg;
221     }
222 
223     output = (tmp != nullptr
224                   ? std::vector<float>(static_cast<float *>(tmp), static_cast<float *>(tmp) + length / sizeof(float))
225                   : std::vector<float>());
226     return status;
227 }
228 
Convert2Value(napi_env env,napi_value jsValue,std::string & output)229 int32_t JSUtils::Convert2Value(napi_env env, napi_value jsValue, std::string &output)
230 {
231     napi_valuetype type = napi_undefined;
232     napi_status status = napi_typeof(env, jsValue, &type);
233     if (status != napi_ok || type != napi_string) {
234         LOG_DEBUG("napi_typeof failed status = %{public}d type = %{public}d", status, type);
235         return napi_invalid_arg;
236     }
237 
238     size_t buffSize = 0;
239     napi_get_value_string_utf8(env, jsValue, nullptr, 0, &buffSize);
240 
241     // cut down with 0 if more than MAX_VALUE_LENGTH
242     if (buffSize >= JSUtils::MAX_VALUE_LENGTH - 1) {
243         buffSize = JSUtils::MAX_VALUE_LENGTH - 1;
244     }
245     std::unique_ptr<char[]> buffer = std::make_unique<char[]>(buffSize + 1);
246     if (!buffer) {
247         LOG_ERROR("buffer data is nullptr.");
248         return napi_invalid_arg;
249     }
250     status = napi_get_value_string_utf8(env, jsValue, buffer.get(), buffSize + 1, &buffSize);
251     if (status != napi_ok) {
252         LOG_ERROR("napi_get_value_string_utf8 failed, status = %{public}d", status);
253         return status;
254     }
255     output = std::string(buffer.get());
256 
257     return status;
258 }
259 
Convert2Value(napi_env env,napi_value jsValue,std::vector<uint8_t> & output)260 int32_t JSUtils::Convert2Value(napi_env env, napi_value jsValue, std::vector<uint8_t> &output)
261 {
262     bool isTypedArray = false;
263     napi_is_typedarray(env, jsValue, &isTypedArray);
264     if (!isTypedArray) {
265         return napi_invalid_arg;
266     }
267 
268     napi_typedarray_type type;
269     napi_value input_buffer = nullptr;
270     size_t byte_offset = 0;
271     size_t length = 0;
272     void *tmp = nullptr;
273     auto status = napi_get_typedarray_info(env, jsValue, &type, &length, &tmp, &input_buffer, &byte_offset);
274     if (status != napi_ok || type != napi_uint8_array) {
275         return napi_invalid_arg;
276     }
277 
278     output = (tmp != nullptr ? std::vector<uint8_t>(static_cast<uint8_t *>(tmp), static_cast<uint8_t *>(tmp) + length)
279                              : std::vector<uint8_t>());
280     return status;
281 }
282 
Convert2Value(napi_env env,napi_value jsValue,std::monostate & value)283 int32_t JSUtils::Convert2Value(napi_env env, napi_value jsValue, std::monostate &value)
284 {
285     napi_value tempValue = nullptr;
286     napi_get_null(env, &tempValue);
287     bool equal = false;
288     napi_strict_equals(env, jsValue, tempValue, &equal);
289     if (equal) {
290         value = std::monostate();
291         return napi_ok;
292     }
293     LOG_DEBUG("jsValue is not null.");
294     return napi_invalid_arg;
295 }
296 
Convert2Value(napi_env env,napi_value jsValue,std::map<std::string,int32_t> & output)297 int32_t JSUtils::Convert2Value(napi_env env, napi_value jsValue, std::map<std::string, int32_t> &output)
298 {
299     LOG_DEBUG("napi_value -> std::map<std::string, int32_t> ");
300     output.clear();
301     napi_value jsMapList = nullptr;
302     uint32_t jsCount = 0;
303     napi_status status = napi_get_property_names(env, jsValue, &jsMapList);
304     CHECK_RETURN_RET(status == napi_ok, "get_property_names failed", napi_invalid_arg);
305     status = napi_get_array_length(env, jsMapList, &jsCount);
306     LOG_DEBUG("jsCOUNT: %{public}d", jsCount);
307     CHECK_RETURN_RET(status == napi_ok && jsCount > 0, "get_map failed", napi_invalid_arg);
308     napi_value jsKey = nullptr;
309     napi_value jsVal = nullptr;
310     for (uint32_t index = 0; index < jsCount; index++) {
311         status = napi_get_element(env, jsMapList, index, &jsKey);
312         CHECK_RETURN_RET(status == napi_ok && jsKey != nullptr, "no element", napi_invalid_arg);
313         std::string key;
314         int ret = Convert2Value(env, jsKey, key);
315         CHECK_RETURN_RET(ret == napi_ok, "convert key failed", ret);
316         status = napi_get_property(env, jsValue, jsKey, &jsVal);
317         CHECK_RETURN_RET(status == napi_ok && jsVal != nullptr, "no element", napi_invalid_arg);
318         int32_t val;
319         ret = Convert2ValueExt(env, jsVal, val);
320         CHECK_RETURN_RET(ret == napi_ok, "convert val failed", ret);
321         output.insert(std::pair<std::string, int32_t>(key, val));
322     }
323     return napi_ok;
324 }
325 
Convert2Value(napi_env env,napi_value jsValue,std::map<std::string,bool> & output)326 int32_t JSUtils::Convert2Value(napi_env env, napi_value jsValue, std::map<std::string, bool> &output)
327 {
328     LOG_DEBUG("napi_value -> std::map<std::string, bool> ");
329     output.clear();
330     napi_value jsMapList = nullptr;
331     uint32_t jsCount = 0;
332     napi_status status = napi_get_property_names(env, jsValue, &jsMapList);
333     CHECK_RETURN_RET(status == napi_ok, "get_property_names failed", napi_invalid_arg);
334     status = napi_get_array_length(env, jsMapList, &jsCount);
335     LOG_DEBUG("jsCount: %{public}d", jsCount);
336     CHECK_RETURN_RET(status == napi_ok && jsCount > 0, "get_map failed", napi_invalid_arg);
337     napi_value jsKey = nullptr;
338     napi_value jsVal = nullptr;
339     for (uint32_t index = 0; index < jsCount; index++) {
340         status = napi_get_element(env, jsMapList, index, &jsKey);
341         CHECK_RETURN_RET(status == napi_ok && jsKey != nullptr, "no element", napi_invalid_arg);
342         std::string key;
343         int ret = Convert2Value(env, jsKey, key);
344         CHECK_RETURN_RET(ret == napi_ok, "convert key failed", ret);
345         status = napi_get_property(env, jsValue, jsKey, &jsVal);
346         CHECK_RETURN_RET(status == napi_ok && jsVal != nullptr, "no element", napi_invalid_arg);
347         bool val;
348         ret = Convert2Value(env, jsVal, val);
349         CHECK_RETURN_RET(ret == napi_ok, "convert val failed", ret);
350         output.insert(std::pair<std::string, bool>(key, val));
351     }
352     return napi_ok;
353 }
354 
Convert2JSValue(napi_env env,const std::string & value)355 napi_value JSUtils::Convert2JSValue(napi_env env, const std::string &value)
356 {
357     napi_value jsValue = nullptr;
358     if (napi_create_string_utf8(env, value.c_str(), value.size(), &jsValue) != napi_ok) {
359         return nullptr;
360     }
361     return jsValue;
362 }
363 
Convert2JSValue(napi_env env,const std::vector<uint8_t> & value)364 napi_value JSUtils::Convert2JSValue(napi_env env, const std::vector<uint8_t> &value)
365 {
366     napi_value jsValue = nullptr;
367     void *native = nullptr;
368     napi_value buffer = nullptr;
369     napi_status status = napi_create_arraybuffer(env, value.size(), &native, &buffer);
370     if (status != napi_ok) {
371         return nullptr;
372     }
373     for (size_t i = 0; i < value.size(); i++) {
374         *(static_cast<uint8_t *>(native) + i) = value[i];
375     }
376     status = napi_create_typedarray(env, napi_uint8_array, value.size(), buffer, 0, &jsValue);
377     if (status != napi_ok) {
378         return nullptr;
379     }
380     return jsValue;
381 }
382 
Convert2JSValue(napi_env env,int32_t value)383 napi_value JSUtils::Convert2JSValue(napi_env env, int32_t value)
384 {
385     napi_value jsValue = nullptr;
386     napi_status status = napi_create_int32(env, value, &jsValue);
387     if (status != napi_ok) {
388         return nullptr;
389     }
390     return jsValue;
391 }
392 
Convert2JSValue(napi_env env,uint32_t value)393 napi_value JSUtils::Convert2JSValue(napi_env env, uint32_t value)
394 {
395     napi_value jsValue = nullptr;
396     napi_status status = napi_create_uint32(env, value, &jsValue);
397     if (status != napi_ok) {
398         return nullptr;
399     }
400     return jsValue;
401 }
402 
Convert2JSValue(napi_env env,int64_t value)403 napi_value JSUtils::Convert2JSValue(napi_env env, int64_t value)
404 {
405     napi_value jsValue = nullptr;
406     napi_status status = napi_create_int64(env, value, &jsValue);
407     if (status != napi_ok) {
408         return nullptr;
409     }
410     return jsValue;
411 }
412 
Convert2JSValue(napi_env env,double value)413 napi_value JSUtils::Convert2JSValue(napi_env env, double value)
414 {
415     napi_value jsValue = nullptr;
416     napi_status status = napi_create_double(env, value, &jsValue);
417     if (status != napi_ok) {
418         return nullptr;
419     }
420     return jsValue;
421 }
422 
Convert2JSValue(napi_env env,bool value)423 napi_value JSUtils::Convert2JSValue(napi_env env, bool value)
424 {
425     napi_value jsValue = nullptr;
426     napi_status status = napi_get_boolean(env, value, &jsValue);
427     if (status != napi_ok) {
428         return nullptr;
429     }
430     return jsValue;
431 }
432 
Convert2JSValue(napi_env env,const std::vector<float> & value)433 napi_value JSUtils::Convert2JSValue(napi_env env, const std::vector<float> &value)
434 {
435     napi_value jsValue = nullptr;
436     float *native = nullptr;
437     napi_value buffer = nullptr;
438     napi_status status = napi_create_arraybuffer(env, value.size() * sizeof(float), (void **)&native, &buffer);
439     if (status != napi_ok) {
440         return nullptr;
441     }
442     if (native == nullptr) {
443         return nullptr;
444     }
445     for (size_t i = 0; i < value.size(); i++) {
446         *(native + i) = value[i];
447     }
448     status = napi_create_typedarray(env, napi_float32_array, value.size(), buffer, 0, &jsValue);
449     if (status != napi_ok) {
450         return nullptr;
451     }
452     return jsValue;
453 }
454 
Convert2JSValue(napi_env env,const std::map<std::string,int> & value)455 napi_value JSUtils::Convert2JSValue(napi_env env, const std::map<std::string, int> &value)
456 {
457     napi_value jsValue = nullptr;
458     napi_status status = napi_create_array_with_length(env, value.size(), &jsValue);
459     if (status != napi_ok) {
460         return nullptr;
461     }
462 
463     int index = 0;
464     for (const auto &[device, result] : value) {
465         napi_value jsElement = nullptr;
466         status = napi_create_array_with_length(env, SYNC_RESULT_ELEMENT_NUM, &jsElement);
467         if (status != napi_ok) {
468             return nullptr;
469         }
470         napi_set_element(env, jsElement, 0, Convert2JSValue(env, device));
471         napi_set_element(env, jsElement, 1, Convert2JSValue(env, result));
472         napi_set_element(env, jsValue, index++, jsElement);
473     }
474 
475     return jsValue;
476 }
477 
Convert2JSValue(napi_env env,std::string value,napi_value & output)478 int32_t JSUtils::Convert2JSValue(napi_env env, std::string value, napi_value &output)
479 {
480     std::string tempStr = std::string(value);
481     if (napi_create_string_utf8(env, tempStr.c_str(), tempStr.size(), &output) != napi_ok) {
482         LOG_ERROR("Convert2JSValue create JS string failed.");
483         return ERR;
484     }
485     return napi_ok;
486 }
487 
Convert2JSValue(napi_env env,bool value,napi_value & output)488 int32_t JSUtils::Convert2JSValue(napi_env env, bool value, napi_value &output)
489 {
490     if (napi_get_boolean(env, value, &output) != napi_ok) {
491         LOG_ERROR("Convert2JSValue create JS bool failed.");
492         return ERR;
493     }
494     return napi_ok;
495 }
496 
Convert2JSValue(napi_env env,double value,napi_value & output)497 int32_t JSUtils::Convert2JSValue(napi_env env, double value, napi_value &output)
498 {
499     if (napi_create_double(env, value, &output) != napi_ok) {
500         LOG_ERROR("Convert2JSValue create JS double failed.");
501         return ERR;
502     }
503     return napi_ok;
504 }
505 
Convert2JSValue(napi_env env,const std::monostate & value)506 napi_value JSUtils::Convert2JSValue(napi_env env, const std::monostate &value)
507 {
508     napi_value result = nullptr;
509     napi_get_null(env, &result);
510     return result;
511 }
512 
IsNull(napi_env env,napi_value value)513 bool JSUtils::IsNull(napi_env env, napi_value value)
514 {
515     napi_valuetype type = napi_undefined;
516     napi_status status = napi_typeof(env, value, &type);
517     return status == napi_ok && (type == napi_undefined || type == napi_null);
518 }
519 
DefineClass(napi_env env,const std::string & spaceName,const std::string & className,const Descriptor & descriptor,napi_callback ctor)520 napi_value JSUtils::DefineClass(napi_env env, const std::string &spaceName, const std::string &className,
521     const Descriptor &descriptor, napi_callback ctor)
522 {
523     auto featureSpace = GetJsFeatureSpace(spaceName);
524     if (!featureSpace.has_value() || !featureSpace->isComponent) {
525         return nullptr;
526     }
527     auto constructor = GetClass(env, spaceName, className);
528     if (constructor != nullptr) {
529         return constructor;
530     }
531     auto rootPropName = std::string(featureSpace->nameBase64);
532     napi_value root = nullptr;
533     bool hasRoot = false;
534     napi_value global = nullptr;
535     napi_get_global(env, &global);
536     napi_has_named_property(env, global, rootPropName.c_str(), &hasRoot);
537     if (hasRoot) {
538         napi_get_named_property(env, global, rootPropName.c_str(), &root);
539     } else {
540         napi_create_object(env, &root);
541         napi_set_named_property(env, global, rootPropName.c_str(), root);
542     }
543 
544     std::string propName = "constructor_of_" + className;
545     bool hasProp = false;
546     napi_has_named_property(env, root, propName.c_str(), &hasProp);
547     if (hasProp) {
548         napi_get_named_property(env, root, propName.c_str(), &constructor);
549         if (constructor != nullptr) {
550             LOG_DEBUG("got %{public}s from %{public}s", propName.c_str(), featureSpace->spaceName);
551             return constructor;
552         }
553         hasProp = false; // no constructor.
554     }
555     auto properties = descriptor();
556     NAPI_CALL(env, napi_define_class(env, className.c_str(), className.size(), ctor, nullptr, properties.size(),
557                        properties.data(), &constructor));
558     NAPI_ASSERT(env, constructor != nullptr, "napi_define_class failed!");
559 
560     if (!hasProp) {
561         napi_set_named_property(env, root, propName.c_str(), constructor);
562         LOG_DEBUG("save %{public}s to %{public}s", propName.c_str(), featureSpace->spaceName);
563     }
564     return constructor;
565 }
566 
GetClass(napi_env env,const std::string & spaceName,const std::string & className)567 napi_value JSUtils::GetClass(napi_env env, const std::string &spaceName, const std::string &className)
568 {
569     auto featureSpace = GetJsFeatureSpace(spaceName);
570     if (!featureSpace.has_value()) {
571         return nullptr;
572     }
573     auto rootPropName = std::string(featureSpace->nameBase64);
574     napi_value root = nullptr;
575     napi_value global = nullptr;
576     napi_get_global(env, &global);
577     bool hasRoot;
578     napi_has_named_property(env, global, rootPropName.c_str(), &hasRoot);
579     if (!hasRoot) {
580         return nullptr;
581     }
582     napi_get_named_property(env, global, rootPropName.c_str(), &root);
583     std::string propName = "constructor_of_" + className;
584     napi_value constructor = nullptr;
585     bool hasProp = false;
586     napi_has_named_property(env, root, propName.c_str(), &hasProp);
587     if (!hasProp) {
588         return nullptr;
589     }
590     napi_get_named_property(env, root, propName.c_str(), &constructor);
591     if (constructor != nullptr) {
592         LOG_DEBUG("got %{public}s from %{public}s", propName.c_str(), featureSpace->spaceName);
593         return constructor;
594     }
595     hasProp = false; // no constructor.
596     return constructor;
597 }
598 
Equal(napi_env env,napi_ref ref,napi_value value)599 bool JSUtils::Equal(napi_env env, napi_ref ref, napi_value value)
600 {
601     napi_value callback = nullptr;
602     napi_get_reference_value(env, ref, &callback);
603 
604     bool isEquals = false;
605     napi_strict_equals(env, value, callback, &isEquals);
606     return isEquals;
607 }
608 
ToJsObject(napi_env env,napi_value sendableValue)609 napi_value JSUtils::ToJsObject(napi_env env, napi_value sendableValue)
610 {
611     LOG_DEBUG("sendableObject -> jsObject");
612     napi_value keys = nullptr;
613     napi_status status = napi_get_all_property_names(env, sendableValue, napi_key_own_only,
614         static_cast<napi_key_filter>(napi_key_enumerable | napi_key_skip_symbols), napi_key_numbers_to_strings, &keys);
615     ASSERT(status == napi_ok, "napi_get_all_property_names failed", nullptr);
616     uint32_t length = 0;
617     status = napi_get_array_length(env, keys, &length);
618     ASSERT(status == napi_ok, "napi_get_array_length failed", nullptr);
619     std::vector<napi_property_descriptor> descriptors;
620     // keysHold guarantees that the string address is valid before create the sendable object.
621     std::vector<std::string> keysHold(length, "");
622     for (uint32_t i = 0; i < length; ++i) {
623         napi_value key = nullptr;
624         status = napi_get_element(env, keys, i, &key);
625         ASSERT(status == napi_ok, "napi_get_element failed", nullptr);
626         JSUtils::Convert2Value(env, key, keysHold[i]);
627         napi_value value = nullptr;
628         status = napi_get_named_property(env, sendableValue, keysHold[i].c_str(), &value);
629         ASSERT(status == napi_ok, "napi_get_named_property failed", nullptr);
630         descriptors.emplace_back(DECLARE_JS_PROPERTY(env, keysHold[i].c_str(), value));
631     }
632     napi_value jsObject = nullptr;
633     status = napi_create_object_with_properties(env, &jsObject, descriptors.size(), descriptors.data());
634     ASSERT(status == napi_ok, "napi_create_object_with_properties failed", nullptr);
635     return jsObject;
636 }
637 
ToJsArray(napi_env env,napi_value sendableValue)638 napi_value JSUtils::ToJsArray(napi_env env, napi_value sendableValue)
639 {
640     LOG_DEBUG("sendableArray -> jsArray");
641     uint32_t arrLen = 0;
642     napi_status status = napi_get_array_length(env, sendableValue, &arrLen);
643     ASSERT(status == napi_ok, "napi_get_array_length failed", nullptr);
644     napi_value jsArray = nullptr;
645     status = napi_create_array_with_length(env, arrLen, &jsArray);
646     ASSERT(status == napi_ok, "napi_create_array_with_length failed", nullptr);
647     for (size_t i = 0; i < arrLen; ++i) {
648         napi_value element;
649         status = napi_get_element(env, sendableValue, i, &element);
650         ASSERT(status == napi_ok, "napi_get_element failed", nullptr);
651         status = napi_set_element(env, jsArray, i, Convert2JSValue(env, element));
652         ASSERT(status == napi_ok, "napi_set_element failed", nullptr);
653     }
654     return jsArray;
655 }
656 
ToJsTypedArray(napi_env env,napi_value sendableValue)657 napi_value JSUtils::ToJsTypedArray(napi_env env, napi_value sendableValue)
658 {
659     LOG_DEBUG("sendableTypedArray -> jsTypedArray");
660     napi_typedarray_type type;
661     size_t length = 0;
662     void *tmp = nullptr;
663     napi_status status = napi_get_typedarray_info(env, sendableValue, &type, &length, &tmp, nullptr, nullptr);
664     ASSERT(status == napi_ok, "napi_get_typedarray_info failed", nullptr);
665 
666     if (type != napi_uint8_array && type != napi_float32_array) {
667         LOG_ERROR("type is invalid %{public}d", type);
668         return nullptr;
669     }
670     napi_value jsTypedArray = nullptr;
671     void *native = nullptr;
672     napi_value buffer = nullptr;
673     status = napi_create_arraybuffer(env, length, (void **)&native, &buffer);
674     ASSERT(status == napi_ok, "napi_create_arraybuffer failed", nullptr);
675     if (length > 0) {
676         errno_t result = memcpy_s(native, length, tmp, length);
677         if (result != EOK) {
678             LOG_ERROR("memcpy_s failed, result is %{public}d", result);
679             return nullptr;
680         }
681     }
682     auto size = (type == napi_uint8_array) ? length : length / sizeof(float);
683     status = napi_create_typedarray(env, type, size, buffer, 0, &jsTypedArray);
684     ASSERT(status == napi_ok, "napi_create_typedarray failed", nullptr);
685     return jsTypedArray;
686 }
687 
Convert2JSValue(napi_env env,napi_value sendableValue)688 napi_value JSUtils::Convert2JSValue(napi_env env, napi_value sendableValue)
689 {
690     napi_valuetype type = napi_undefined;
691     napi_status status = napi_typeof(env, sendableValue, &type);
692     ASSERT(status == napi_ok, "napi_typeof failed", nullptr);
693     if (type != napi_object) {
694         return sendableValue;
695     }
696     bool result = false;
697     status = napi_is_sendable(env, sendableValue, &result);
698     ASSERT(status == napi_ok, "napi_is_sendable failed", nullptr);
699     if (!result) {
700         return sendableValue;
701     }
702 
703     status = napi_is_array(env, sendableValue, &result);
704     ASSERT(status == napi_ok, "napi_is_array failed", nullptr);
705     if (result) {
706         return ToJsArray(env, sendableValue);
707     }
708     status = napi_is_typedarray(env, sendableValue, &result);
709     ASSERT(status == napi_ok, "napi_is_typedarray failed", nullptr);
710     if (result) {
711         return ToJsTypedArray(env, sendableValue);
712     }
713     return ToJsObject(env, sendableValue);
714 }
715 } // namespace AppDataMgrJsKit
716 } // namespace OHOS