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