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