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