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