1 /*
2  * Copyright (c) 2022 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 "JSUtil"
16 #include "js_util.h"
17 #include <endian.h>
18 #include <securec.h>
19 #include "ability.h"
20 #include "hap_module_info.h"
21 #include "js_schema.h"
22 #include "kv_utils.h"
23 #include "log_print.h"
24 #include "napi_base_context.h"
25 #include "napi_queue.h"
26 #include "types.h"
27 
28 using namespace OHOS::DistributedKv;
29 using namespace OHOS::DataShare;
30 namespace OHOS::DistributedData {
31 constexpr int32_t STR_MAX_LENGTH = 4096;
32 constexpr size_t STR_TAIL_LENGTH = 1;
33 struct PredicatesProxy {
34     std::shared_ptr<DataShareAbsPredicates> predicates_;
35 };
36 
GetValue(napi_env env,napi_value in,napi_value & out)37 napi_status JSUtil::GetValue(napi_env env, napi_value in, napi_value& out)
38 {
39     out = in;
40     return napi_ok;
41 }
42 
SetValue(napi_env env,napi_value in,napi_value & out)43 napi_status JSUtil::SetValue(napi_env env, napi_value in, napi_value& out)
44 {
45     out = in;
46     return napi_ok;
47 }
48 
49 /* napi_value <-> bool */
GetValue(napi_env env,napi_value in,bool & out)50 napi_status JSUtil::GetValue(napi_env env, napi_value in, bool& out)
51 {
52     return napi_get_value_bool(env, in, &out);
53 }
54 
SetValue(napi_env env,const bool & in,napi_value & out)55 napi_status JSUtil::SetValue(napi_env env, const bool& in, napi_value& out)
56 {
57     return napi_get_boolean(env, in, &out);
58 }
59 
60 /* napi_value <-> int32_t */
GetValue(napi_env env,napi_value in,int32_t & out)61 napi_status JSUtil::GetValue(napi_env env, napi_value in, int32_t& out)
62 {
63     return napi_get_value_int32(env, in, &out);
64 }
65 
SetValue(napi_env env,const int32_t & in,napi_value & out)66 napi_status JSUtil::SetValue(napi_env env, const int32_t& in, napi_value& out)
67 {
68     return napi_create_int32(env, in, &out);
69 }
70 
71 /* napi_value <-> uint32_t */
GetValue(napi_env env,napi_value in,uint32_t & out)72 napi_status JSUtil::GetValue(napi_env env, napi_value in, uint32_t& out)
73 {
74     return napi_get_value_uint32(env, in, &out);
75 }
76 
SetValue(napi_env env,const uint32_t & in,napi_value & out)77 napi_status JSUtil::SetValue(napi_env env, const uint32_t& in, napi_value& out)
78 {
79     return napi_create_uint32(env, in, &out);
80 }
81 
82 /* napi_value <-> int64_t */
GetValue(napi_env env,napi_value in,int64_t & out)83 napi_status JSUtil::GetValue(napi_env env, napi_value in, int64_t& out)
84 {
85     return napi_get_value_int64(env, in, &out);
86 }
87 
SetValue(napi_env env,const int64_t & in,napi_value & out)88 napi_status JSUtil::SetValue(napi_env env, const int64_t& in, napi_value& out)
89 {
90     return napi_create_int64(env, in, &out);
91 }
92 
93 /* napi_value <-> double */
GetValue(napi_env env,napi_value in,double & out)94 napi_status JSUtil::GetValue(napi_env env, napi_value in, double& out)
95 {
96     return napi_get_value_double(env, in, &out);
97 }
98 
SetValue(napi_env env,const double & in,napi_value & out)99 napi_status JSUtil::SetValue(napi_env env, const double& in, napi_value& out)
100 {
101     return napi_create_double(env, in, &out);
102 }
103 
104 /* napi_value <-> std::string */
GetValue(napi_env env,napi_value in,std::string & out)105 napi_status JSUtil::GetValue(napi_env env, napi_value in, std::string& out)
106 {
107     napi_valuetype type = napi_undefined;
108     napi_status status = napi_typeof(env, in, &type);
109     CHECK_RETURN((status == napi_ok) && (type == napi_string), "invalid type", napi_invalid_arg);
110 
111     size_t maxLen = STR_MAX_LENGTH;
112     status = napi_get_value_string_utf8(env, in, NULL, 0, &maxLen);
113     if (maxLen <= 0) {
114         return status;
115     }
116     ZLOGD("napi_value -> std::string get length %{public}d", (int)maxLen);
117     char* buf = new (std::nothrow) char[maxLen + STR_TAIL_LENGTH];
118     if (buf != nullptr) {
119         size_t len = 0;
120         status = napi_get_value_string_utf8(env, in, buf, maxLen + STR_TAIL_LENGTH, &len);
121         if (status == napi_ok) {
122             buf[len] = 0;
123             out = std::string(buf);
124         }
125         delete[] buf;
126     } else {
127         status = napi_generic_failure;
128     }
129     return status;
130 }
131 
SetValue(napi_env env,const std::string & in,napi_value & out)132 napi_status JSUtil::SetValue(napi_env env, const std::string& in, napi_value& out)
133 {
134     return napi_create_string_utf8(env, in.c_str(), in.size(), &out);
135 }
136 
137 /* napi_value <-> std::vector<std::string> */
GetValue(napi_env env,napi_value in,std::vector<std::string> & out,bool checkLength)138 napi_status JSUtil::GetValue(napi_env env, napi_value in, std::vector<std::string>& out, bool checkLength)
139 {
140     ZLOGD("napi_value -> std::vector<std::string>");
141     out.clear();
142     bool isArray = false;
143     napi_is_array(env, in, &isArray);
144     CHECK_RETURN(isArray, "not an array", napi_invalid_arg);
145 
146     uint32_t length = 0;
147     napi_status status = napi_get_array_length(env, in, &length);
148     CHECK_RETURN(status == napi_ok, "get_array length failed!", napi_invalid_arg);
149     if (checkLength) {
150         CHECK_RETURN(length > 0, "check array length failed!", napi_invalid_arg);
151     }
152     for (uint32_t i = 0; i < length; ++i) {
153         napi_value item = nullptr;
154         status = napi_get_element(env, in, i, &item);
155         CHECK_RETURN((item != nullptr) && (status == napi_ok), "no element", napi_invalid_arg);
156         std::string value;
157         status = GetValue(env, item, value);
158         CHECK_RETURN(status == napi_ok, "not a string", napi_invalid_arg);
159         out.push_back(value);
160     }
161     return status;
162 }
163 
SetValue(napi_env env,const std::vector<std::string> & in,napi_value & out)164 napi_status JSUtil::SetValue(napi_env env, const std::vector<std::string>& in, napi_value& out)
165 {
166     ZLOGD("napi_value <- std::vector<std::string>");
167     napi_status status = napi_create_array_with_length(env, in.size(), &out);
168     CHECK_RETURN(status == napi_ok, "create array failed!", status);
169     int index = 0;
170     for (auto& item : in) {
171         napi_value element = nullptr;
172         SetValue(env, item, element);
173         status = napi_set_element(env, out, index++, element);
174         CHECK_RETURN((status == napi_ok), "napi_set_element failed!", status);
175     }
176     return status;
177 }
178 
Blob2VariantValue(const DistributedKv::Blob & blob)179 JSUtil::KvStoreVariant JSUtil::Blob2VariantValue(const DistributedKv::Blob& blob)
180 {
181     auto& data = blob.Data();
182     // number 2 means: valid Blob must have more than 2 bytes.
183     if (data.size() < 1) {
184         ZLOGE("Blob have no data!");
185         return JSUtil::KvStoreVariant();
186     }
187     // number 1 means: skip the first byte, byte[0] is real data type.
188     std::vector<uint8_t> real(data.begin() + 1, data.end());
189     ZLOGD("Blob::type %{public}d size=%{public}d", static_cast<int>(data[0]), static_cast<int>(real.size()));
190     if (data[0] == JSUtil::INTEGER) {
191         uint32_t tmp = be32toh(*reinterpret_cast<uint32_t*>(&(real[0])));
192         return JSUtil::KvStoreVariant(static_cast<int32_t>(tmp));
193     } else if (data[0] == JSUtil::FLOAT) {
194         uint32_t tmp = be32toh(*reinterpret_cast<uint32_t*>(&(real[0])));
195         return JSUtil::KvStoreVariant(*reinterpret_cast<float*>((void*)(&tmp)));
196     } else if (data[0] == JSUtil::BYTE_ARRAY) {
197         return JSUtil::KvStoreVariant(std::vector<uint8_t>(real.begin(), real.end()));
198     } else if (data[0] == JSUtil::BOOLEAN) {
199         return JSUtil::KvStoreVariant(static_cast<bool>(real[0]));
200     } else if (data[0] == JSUtil::DOUBLE) {
201         uint64_t tmp = be64toh(*reinterpret_cast<uint64_t*>(&(real[0])));
202         return JSUtil::KvStoreVariant(*reinterpret_cast<double*>((void*)(&tmp)));
203     } else if (data[0] == JSUtil::STRING) {
204         return JSUtil::KvStoreVariant(std::string(real.begin(), real.end()));
205     } else {
206         // for schema-db, if (data[0] == JSUtil::STRING), no beginning byte!
207         return JSUtil::KvStoreVariant(std::string(data.begin(), data.end()));
208     }
209 }
210 
VariantValue2Blob(const JSUtil::KvStoreVariant & value)211 DistributedKv::Blob JSUtil::VariantValue2Blob(const JSUtil::KvStoreVariant& value)
212 {
213     std::vector<uint8_t> data;
214     auto strValue = std::get_if<std::string>(&value);
215     if (strValue != nullptr) {
216         data.push_back(JSUtil::STRING);
217         data.insert(data.end(), (*strValue).begin(), (*strValue).end());
218     }
219     auto u8ArrayValue = std::get_if<std::vector<uint8_t>>(&value);
220     if (u8ArrayValue != nullptr) {
221         data.push_back(JSUtil::BYTE_ARRAY);
222         data.insert(data.end(), (*u8ArrayValue).begin(), (*u8ArrayValue).end());
223     }
224     auto boolValue = std::get_if<bool>(&value);
225     if (boolValue != nullptr) {
226         data.push_back(JSUtil::BOOLEAN);
227         data.push_back(static_cast<uint8_t>(*boolValue));
228     }
229     uint8_t *res = nullptr;
230     auto intValue = std::get_if<int32_t>(&value);
231     if (intValue != nullptr) {
232         uint32_t tmp = static_cast<uint32_t>(*intValue); // copy value, and make it available in stack space.
233         tmp = htobe32(tmp);
234         res = reinterpret_cast<uint8_t*>(&tmp);
235         data.push_back(JSUtil::INTEGER);
236         data.insert(data.end(), res, res + sizeof(int32_t) / sizeof(uint8_t));
237     }
238     auto fltValue = std::get_if<float>(&value);
239     if (fltValue != nullptr) {
240         float tmp = *fltValue; // copy value, and make it available in stack space.
241         uint32_t tmp32 = htobe32(*reinterpret_cast<uint32_t*>(&tmp));
242         res = reinterpret_cast<uint8_t*>(&tmp32);
243         data.push_back(JSUtil::FLOAT);
244         data.insert(data.end(), res, res + sizeof(float) / sizeof(uint8_t));
245     }
246     auto dblValue = std::get_if<double>(&value);
247     if (dblValue != nullptr) {
248         double tmp = *dblValue; // copy value, and make it available in stack space.
249         uint64_t tmp64 = htobe64(*reinterpret_cast<uint64_t*>(&tmp));
250         res = reinterpret_cast<uint8_t*>(&tmp64);
251         data.push_back(JSUtil::DOUBLE);
252         data.insert(data.end(), res, res + sizeof(double) / sizeof(uint8_t));
253     }
254     return DistributedKv::Blob(data);
255 }
256 
257 /* napi_value <-> KvStoreVariant */
GetValue(napi_env env,napi_value in,JSUtil::KvStoreVariant & out)258 napi_status JSUtil::GetValue(napi_env env, napi_value in, JSUtil::KvStoreVariant& out)
259 {
260     napi_valuetype type = napi_undefined;
261     napi_status status = napi_typeof(env, in, &type);
262     CHECK_RETURN((status == napi_ok), "invalid type", status);
263     switch (type) {
264         case napi_boolean: {
265             bool vBool = false;
266             status = JSUtil::GetValue(env, in, vBool);
267             out = vBool;
268             break;
269         }
270         case napi_number: {
271             double vNum = 0.0;
272             status = JSUtil::GetValue(env, in, vNum);
273             out = vNum;
274             break;
275         }
276         case napi_string: {
277             std::string vString;
278             status = JSUtil::GetValue(env, in, vString);
279             out = vString;
280             break;
281         }
282         case napi_object: {
283             std::vector<uint8_t> vct;
284             status = JSUtil::GetValue(env, in, vct);
285             out = vct;
286             break;
287         }
288         default:
289             ZLOGE("napi_value -> KvStoreVariant not [Uint8Array | string | boolean | number] type=%{public}d", type);
290             status = napi_invalid_arg;
291             break;
292     }
293     return status;
294 }
295 
SetValue(napi_env env,const JSUtil::KvStoreVariant & in,napi_value & out)296 napi_status JSUtil::SetValue(napi_env env, const JSUtil::KvStoreVariant& in, napi_value& out)
297 {
298     auto strValue = std::get_if<std::string>(&in);
299     if (strValue != nullptr) {
300         return SetValue(env, *strValue, out);
301     }
302     auto intValue = std::get_if<int32_t>(&in);
303     if (intValue != nullptr) {
304         return SetValue(env, *intValue, out);
305     }
306     auto fltValue = std::get_if<float>(&in);
307     if (fltValue != nullptr) {
308         return SetValue(env, *fltValue, out);
309     }
310     auto pUint8 = std::get_if<std::vector<uint8_t>>(&in);
311     if (pUint8 != nullptr) {
312         return SetValue(env, *pUint8, out);
313     }
314     auto boolValue = std::get_if<bool>(&in);
315     if (boolValue != nullptr) {
316         return SetValue(env, *boolValue, out);
317     }
318     auto dblValue = std::get_if<double>(&in);
319     if (dblValue != nullptr) {
320         return SetValue(env, *dblValue, out);
321     }
322 
323     ZLOGE("napi_value <- KvStoreVariant  INVALID value type");
324     return napi_invalid_arg;
325 }
326 
327 /* napi_value <-> QueryVariant */
GetValue(napi_env env,napi_value in,JSUtil::QueryVariant & out)328 napi_status JSUtil::GetValue(napi_env env, napi_value in, JSUtil::QueryVariant& out)
329 {
330     napi_valuetype type = napi_undefined;
331     napi_status status = napi_typeof(env, in, &type);
332     CHECK_RETURN((status == napi_ok), "invalid type", status);
333     ZLOGD("napi_value -> QueryVariant  type=%{public}d", type);
334     switch (type) {
335         case napi_boolean: {
336             bool vBool = false;
337             status = JSUtil::GetValue(env, in, vBool);
338             out = vBool;
339             break;
340         }
341         case napi_number: {
342             double vNum = 0.0;
343             status = JSUtil::GetValue(env, in, vNum);
344             out = vNum;
345             break;
346         }
347         case napi_string: {
348             std::string vString;
349             status = JSUtil::GetValue(env, in, vString);
350             out = vString;
351             break;
352         }
353         default:
354             status = napi_invalid_arg;
355             break;
356     }
357     CHECK_RETURN((status == napi_ok), "napi_value -> QueryVariant bad value!", status);
358     return status;
359 }
360 
SetValue(napi_env env,const JSUtil::QueryVariant & in,napi_value & out)361 napi_status JSUtil::SetValue(napi_env env, const JSUtil::QueryVariant& in, napi_value& out)
362 {
363     ZLOGD("napi_value <- QueryVariant ");
364     napi_status status = napi_invalid_arg;
365     auto strValue = std::get_if<std::string>(&in);
366     if (strValue != nullptr) {
367         status = SetValue(env, *strValue, out);
368     }
369     auto boolValue = std::get_if<bool>(&in);
370     if (boolValue != nullptr) {
371         status = SetValue(env, *boolValue, out);
372     }
373     auto dblValue = std::get_if<double>(&in);
374     if (dblValue != nullptr) {
375         status = SetValue(env, *dblValue, out);
376     } else {
377         ZLOGD("napi_value <- QueryVariant  INVALID value type");
378     }
379     return status;
380 }
381 
382 /* napi_value <-> std::vector<uint8_t> */
GetValue(napi_env env,napi_value in,std::vector<uint8_t> & out)383 napi_status JSUtil::GetValue(napi_env env, napi_value in, std::vector<uint8_t>& out)
384 {
385     out.clear();
386     ZLOGD("napi_value -> std::vector<uint8_t> ");
387     napi_typedarray_type type = napi_biguint64_array;
388     size_t length = 0;
389     napi_value buffer = nullptr;
390     size_t offset = 0;
391     void* data = nullptr;
392     napi_status status = napi_get_typedarray_info(env, in, &type, &length, &data, &buffer, &offset);
393     ZLOGD("array type=%{public}d length=%{public}d offset=%{public}d", (int)type, (int)length, (int)offset);
394     CHECK_RETURN(status == napi_ok, "napi_get_typedarray_info failed!", napi_invalid_arg);
395     CHECK_RETURN(type == napi_uint8_array, "is not Uint8Array!", napi_invalid_arg);
396     CHECK_RETURN((length > 0) && (data != nullptr), "invalid data!", napi_invalid_arg);
397     out.assign((uint8_t*)data, ((uint8_t*)data) + length);
398     return status;
399 }
400 
SetValue(napi_env env,const std::vector<uint8_t> & in,napi_value & out)401 napi_status JSUtil::SetValue(napi_env env, const std::vector<uint8_t>& in, napi_value& out)
402 {
403     ZLOGD("napi_value <- std::vector<uint8_t> ");
404     CHECK_RETURN(in.size() > 0, "invalid std::vector<uint8_t>", napi_invalid_arg);
405     void* data = nullptr;
406     napi_value buffer = nullptr;
407     napi_status status = napi_create_arraybuffer(env, in.size(), &data, &buffer);
408     CHECK_RETURN((status == napi_ok), "create array buffer failed!", status);
409 
410     if (memcpy_s(data, in.size(), in.data(), in.size()) != EOK) {
411         ZLOGE("napi_value <- std::vector<uint8_t>: memcpy_s failed, vector size:%{public}zd", in.size());
412         return napi_invalid_arg;
413     }
414     status = napi_create_typedarray(env, napi_uint8_array, in.size(), buffer, 0, &out);
415     CHECK_RETURN((status == napi_ok), "napi_value <- std::vector<uint8_t> invalid value", status);
416     return status;
417 }
418 
419 template <typename T>
TypedArray2Vector(uint8_t * data,size_t length,napi_typedarray_type type,std::vector<T> & out)420 void TypedArray2Vector(uint8_t* data, size_t length, napi_typedarray_type type, std::vector<T>& out)
421 {
422     auto convert = [&out](auto* data, size_t elements) {
423         for (size_t index = 0; index < elements; index++) {
424             out.push_back(static_cast<T>(data[index]));
425         }
426     };
427 
428     switch (type) {
429         case napi_int8_array:
430             convert(reinterpret_cast<int8_t*>(data), length);
431             break;
432         case napi_uint8_array:
433             convert(data, length);
434             break;
435         case napi_uint8_clamped_array:
436             convert(data, length);
437             break;
438         case napi_int16_array:
439             convert(reinterpret_cast<int16_t*>(data), length / sizeof(int16_t));
440             break;
441         case napi_uint16_array:
442             convert(reinterpret_cast<uint16_t*>(data), length / sizeof(uint16_t));
443             break;
444         case napi_int32_array:
445             convert(reinterpret_cast<int32_t*>(data), length / sizeof(int32_t));
446             break;
447         case napi_uint32_array:
448             convert(reinterpret_cast<uint32_t*>(data), length / sizeof(uint32_t));
449             break;
450         case napi_float32_array:
451             convert(reinterpret_cast<float*>(data), length / sizeof(float));
452             break;
453         case napi_float64_array:
454             convert(reinterpret_cast<double*>(data), length / sizeof(double));
455             break;
456         case napi_bigint64_array:
457             convert(reinterpret_cast<int64_t*>(data), length / sizeof(int64_t));
458             break;
459         case napi_biguint64_array:
460             convert(reinterpret_cast<uint64_t*>(data), length / sizeof(uint64_t));
461             break;
462         default:
463             CHECK_RETURN_VOID(false, "[FATAL] invalid napi_typedarray_type!");
464     }
465 }
466 
467 /* napi_value <-> std::vector<int32_t> */
GetValue(napi_env env,napi_value in,std::vector<int32_t> & out)468 napi_status JSUtil::GetValue(napi_env env, napi_value in, std::vector<int32_t>& out)
469 {
470     out.clear();
471     ZLOGD("napi_value -> std::vector<int32_t> ");
472     napi_typedarray_type type = napi_biguint64_array;
473     size_t length = 0;
474     napi_value buffer = nullptr;
475     size_t offset = 0;
476     uint8_t* data = nullptr;
477     napi_status status = napi_get_typedarray_info(env, in, &type, &length,
478                                                   reinterpret_cast<void**>(&data), &buffer, &offset);
479     ZLOGD("array type=%{public}d length=%{public}d offset=%{public}d", (int)type, (int)length, (int)offset);
480     CHECK_RETURN(status == napi_ok, "napi_get_typedarray_info failed!", napi_invalid_arg);
481     CHECK_RETURN(type <= napi_int32_array, "is not int32 supported typed array!", napi_invalid_arg);
482     CHECK_RETURN((length > 0) && (data != nullptr), "invalid data!", napi_invalid_arg);
483     TypedArray2Vector<int32_t>(data, length, type, out);
484     return status;
485 }
486 
SetValue(napi_env env,const std::vector<int32_t> & in,napi_value & out)487 napi_status JSUtil::SetValue(napi_env env, const std::vector<int32_t>& in, napi_value& out)
488 {
489     ZLOGD("napi_value <- std::vector<int32_t> ");
490     size_t bytes = in.size() * sizeof(int32_t);
491     CHECK_RETURN(bytes > 0, "invalid std::vector<int32_t>", napi_invalid_arg);
492     void* data = nullptr;
493     napi_value buffer = nullptr;
494     napi_status status = napi_create_arraybuffer(env, bytes, &data, &buffer);
495     CHECK_RETURN((status == napi_ok), "invalid buffer", status);
496 
497     if (memcpy_s(data, bytes, in.data(), bytes) != EOK) {
498         ZLOGE("napi_value <- std::vector<int32_t>: memcpy_s failed, vector size:%{public}zd", in.size());
499         return napi_invalid_arg;
500     }
501     status = napi_create_typedarray(env, napi_int32_array, in.size(), buffer, 0, &out);
502     CHECK_RETURN((status == napi_ok), "invalid buffer", status);
503     return status;
504 }
505 
506 /* napi_value <-> std::vector<uint32_t> */
GetValue(napi_env env,napi_value in,std::vector<uint32_t> & out)507 napi_status JSUtil::GetValue(napi_env env, napi_value in, std::vector<uint32_t>& out)
508 {
509     out.clear();
510     ZLOGD("napi_value -> std::vector<uint32_t> ");
511     napi_typedarray_type type = napi_biguint64_array;
512     size_t length = 0;
513     napi_value buffer = nullptr;
514     size_t offset = 0;
515     uint8_t* data = nullptr;
516     napi_status status = napi_get_typedarray_info(env, in, &type, &length,
517                                                   reinterpret_cast<void**>(&data), &buffer, &offset);
518     ZLOGD("napi_get_typedarray_info type=%{public}d", (int)type);
519     CHECK_RETURN(status == napi_ok, "napi_get_typedarray_info failed!", napi_invalid_arg);
520     CHECK_RETURN((type <= napi_uint16_array) || (type == napi_uint32_array), "invalid type!", napi_invalid_arg);
521     CHECK_RETURN((length > 0) && (data != nullptr), "invalid data!", napi_invalid_arg);
522     TypedArray2Vector<uint32_t>(data, length, type, out);
523     return status;
524 }
525 
SetValue(napi_env env,const std::vector<uint32_t> & in,napi_value & out)526 napi_status JSUtil::SetValue(napi_env env, const std::vector<uint32_t>& in, napi_value& out)
527 {
528     ZLOGD("napi_value <- std::vector<uint32_t> ");
529     size_t bytes = in.size() * sizeof(uint32_t);
530     CHECK_RETURN(bytes > 0, "invalid std::vector<uint32_t>", napi_invalid_arg);
531     void* data = nullptr;
532     napi_value buffer = nullptr;
533     napi_status status = napi_create_arraybuffer(env, bytes, &data, &buffer);
534     CHECK_RETURN((status == napi_ok), "invalid buffer", status);
535 
536     if (memcpy_s(data, bytes, in.data(), bytes) != EOK) {
537         ZLOGE("napi_value <- std::vector<uint32_t>: memcpy_s failed, vector size:%{public}zd", in.size());
538         return napi_invalid_arg;
539     }
540     status = napi_create_typedarray(env, napi_uint32_array, in.size(), buffer, 0, &out);
541     CHECK_RETURN((status == napi_ok), "invalid buffer", status);
542     return status;
543 }
544 
545 /* napi_value <-> std::vector<int64_t> */
GetValue(napi_env env,napi_value in,std::vector<int64_t> & out)546 napi_status JSUtil::GetValue(napi_env env, napi_value in, std::vector<int64_t>& out)
547 {
548     out.clear();
549     ZLOGD("napi_value -> std::vector<int64_t> ");
550     napi_typedarray_type type = napi_biguint64_array;
551     size_t length = 0;
552     napi_value buffer = nullptr;
553     size_t offset = 0;
554     uint8_t* data = nullptr;
555     napi_status status = napi_get_typedarray_info(env, in, &type, &length,
556                                                   reinterpret_cast<void**>(&data), &buffer, &offset);
557     ZLOGD("array type=%{public}d length=%{public}d offset=%{public}d", (int)type, (int)length, (int)offset);
558     CHECK_RETURN(status == napi_ok, "napi_get_typedarray_info failed!", napi_invalid_arg);
559     CHECK_RETURN((type <= napi_uint32_array) || (type == napi_bigint64_array), "invalid type!", napi_invalid_arg);
560     CHECK_RETURN((length > 0) && (data != nullptr), "invalid data!", napi_invalid_arg);
561     TypedArray2Vector<int64_t>(data, length, type, out);
562     return status;
563 }
564 
SetValue(napi_env env,const std::vector<int64_t> & in,napi_value & out)565 napi_status JSUtil::SetValue(napi_env env, const std::vector<int64_t>& in, napi_value& out)
566 {
567     ZLOGD("napi_value <- std::vector<int64_t> ");
568     size_t bytes = in.size() * sizeof(int64_t);
569     CHECK_RETURN(bytes > 0, "invalid std::vector<uint32_t>", napi_invalid_arg);
570     void* data = nullptr;
571     napi_value buffer = nullptr;
572     napi_status status = napi_create_arraybuffer(env, bytes, &data, &buffer);
573     CHECK_RETURN((status == napi_ok), "invalid buffer", status);
574 
575     if (memcpy_s(data, bytes, in.data(), bytes) != EOK) {
576         ZLOGE("napi_value <- std::vector<int64_t>: memcpy_s failed, vector size:%{public}zd", in.size());
577         return napi_invalid_arg;
578     }
579     status = napi_create_typedarray(env, napi_bigint64_array, in.size(), buffer, 0, &out);
580     CHECK_RETURN((status == napi_ok), "invalid buffer", status);
581     return status;
582 }
583 /* napi_value <-> std::vector<double> */
GetValue(napi_env env,napi_value in,std::vector<double> & out)584 napi_status JSUtil::GetValue(napi_env env, napi_value in, std::vector<double>& out)
585 {
586     out.clear();
587     bool isTypedArray = false;
588     napi_status status = napi_is_typedarray(env, in, &isTypedArray);
589     ZLOGD("napi_value -> std::vector<double> input %{public}s a TypedArray", isTypedArray ? "is" : "is not");
590     CHECK_RETURN((status == napi_ok), "napi_is_typedarray failed!", status);
591     if (isTypedArray) {
592         ZLOGD("napi_value -> std::vector<double> ");
593         napi_typedarray_type type = napi_biguint64_array;
594         size_t length = 0;
595         napi_value buffer = nullptr;
596         size_t offset = 0;
597         uint8_t* data = nullptr;
598         status = napi_get_typedarray_info(env, in, &type, &length, reinterpret_cast<void**>(&data), &buffer, &offset);
599         ZLOGD("napi_get_typedarray_info status=%{public}d type=%{public}d", status, (int)type);
600         CHECK_RETURN(status == napi_ok, "napi_get_typedarray_info failed!", napi_invalid_arg);
601         CHECK_RETURN((length > 0) && (data != nullptr), "invalid data!", napi_invalid_arg);
602         TypedArray2Vector<double>(data, length, type, out);
603     } else {
604         bool isArray = false;
605         status = napi_is_array(env, in, &isArray);
606         ZLOGD("napi_value -> std::vector<double> input %{public}s an Array", isArray ? "is" : "is not");
607         CHECK_RETURN((status == napi_ok) && isArray, "invalid data!", napi_invalid_arg);
608         uint32_t length = 0;
609         status = napi_get_array_length(env, in, &length);
610         CHECK_RETURN((status == napi_ok) && (length > 0), "invalid data!", napi_invalid_arg);
611         for (uint32_t i = 0; i < length; ++i) {
612             napi_value item = nullptr;
613             status = napi_get_element(env, in, i, &item);
614             CHECK_RETURN((item != nullptr) && (status == napi_ok), "no element", napi_invalid_arg);
615             double vi = 0.0;
616             status = napi_get_value_double(env, item, &vi);
617             CHECK_RETURN(status == napi_ok, "element is not a double", napi_invalid_arg);
618             out.push_back(vi);
619         }
620     }
621     return status;
622 }
623 
SetValue(napi_env env,const std::vector<double> & in,napi_value & out)624 napi_status JSUtil::SetValue(napi_env env, const std::vector<double>& in, napi_value& out)
625 {
626     ZLOGD("napi_value <- std::vector<double> ");
627     (void)(env);
628     (void)(in);
629     (void)(out);
630     CHECK_RETURN(false, "std::vector<double> to napi_value, unsupported!", napi_invalid_arg);
631     return napi_invalid_arg;
632 }
633 
634 /* napi_value <-> std::map<std::string, int32_t> */
GetValue(napi_env env,napi_value in,std::map<std::string,DistributedKv::Status> & out)635 napi_status JSUtil::GetValue(napi_env env, napi_value in, std::map<std::string, DistributedKv::Status>& out)
636 {
637     ZLOGD("napi_value -> std::map<std::string, int32_t> ");
638     (void)(env);
639     (void)(in);
640     (void)(out);
641     CHECK_RETURN(false, "std::map<std::string, uint32_t> from napi_value, unsupported!", napi_invalid_arg);
642     return napi_invalid_arg;
643 }
644 
SetValue(napi_env env,const std::map<std::string,DistributedKv::Status> & in,napi_value & out)645 napi_status JSUtil::SetValue(napi_env env, const std::map<std::string, DistributedKv::Status>& in, napi_value& out)
646 {
647     ZLOGD("napi_value <- std::map<std::string, int32_t> ");
648     napi_status status = napi_create_array_with_length(env, in.size(), &out);
649     CHECK_RETURN((status == napi_ok), "invalid object", status);
650     int index = 0;
651     for (const auto& [key, value] : in) {
652         napi_value element = nullptr;
653         napi_create_array_with_length(env, TUPLE_SIZE, &element);
654         napi_value jsKey = nullptr;
655         napi_create_string_utf8(env, key.c_str(), key.size(), &jsKey);
656         napi_set_element(env, element, TUPLE_KEY, jsKey);
657         napi_value jsValue = nullptr;
658         napi_create_int32(env, static_cast<int32_t>(value), &jsValue);
659         napi_set_element(env, element, TUPLE_VALUE, jsValue);
660         napi_set_element(env, out, index++, element);
661     }
662     return status;
663 }
664 
665 /*
666  *  interface Value {
667  *       type: ValueType;
668  *       value: Uint8Array | string | number | boolean;
669  *   }
670  *    interface Entry {
671  *        key: string;
672  *        value: Value;
673  *  }
674  */
675 /* napi_value <-> DistributedKv::Entry */
GetValue(napi_env env,napi_value in,DistributedKv::Entry & out,bool hasSchema)676 napi_status JSUtil::GetValue(napi_env env, napi_value in, DistributedKv::Entry& out, bool hasSchema)
677 {
678     ZLOGD("napi_value -> DistributedKv::Entry ");
679     napi_value propKey = nullptr;
680     napi_status status = napi_get_named_property(env, in, "key", &propKey);
681     CHECK_RETURN((status == napi_ok), "no property key", status);
682     std::string key;
683     status = GetValue(env, propKey, key);
684     CHECK_RETURN((status == napi_ok), "no value of key", status);
685 
686     napi_value propValue = nullptr;
687     status = napi_get_named_property(env, in, "value", &propValue);
688     CHECK_RETURN((status == napi_ok), "no property value", status);
689 
690     napi_value propVType = nullptr;
691     status = napi_get_named_property(env, propValue, "type", &propVType);
692     CHECK_RETURN((status == napi_ok), "no property value.type", status);
693     int32_t type = 0;
694     status = GetValue(env, propVType, type);
695     CHECK_RETURN((status == napi_ok), "no value of value.type", status);
696 
697     napi_value propVValue = nullptr;
698     status = napi_get_named_property(env, propValue, "value", &propVValue);
699     CHECK_RETURN((status == napi_ok), "no property value.value", status);
700     KvStoreVariant value = 0;
701     status = GetValue(env, propVValue, value);
702     CHECK_RETURN((status == napi_ok), "no value of value.value", status);
703 
704     out.key = key;
705     if (hasSchema) {
706         out.value = std::get<std::string>(value);
707     } else {
708         out.value = JSUtil::VariantValue2Blob(value);
709     }
710     if (type != out.value[0]) {
711         ZLOGE("unmatch type[%{public}d] to value.type[%{public}d]", (int)type, (int)out.value[0]);
712     }
713     return status;
714 }
715 
SetValue(napi_env env,const DistributedKv::Entry & in,napi_value & out,bool hasSchema)716 napi_status JSUtil::SetValue(napi_env env, const DistributedKv::Entry& in, napi_value& out, bool hasSchema)
717 {
718     ZLOGD("napi_value <- DistributedKv::Entry ");
719     napi_status status = napi_create_object(env, &out);
720     CHECK_RETURN((status == napi_ok), "invalid entry object", status);
721 
722     napi_value key = nullptr;
723     status = SetValue(env, in.key.ToString(), key);
724     CHECK_RETURN((status == napi_ok), "invalid entry key", status);
725     napi_set_named_property(env, out, "key", key);
726 
727     CHECK_RETURN((in.value.Size() > 0), "invalid entry value", status);
728     napi_value value = nullptr;
729 
730     status = napi_create_object(env, &value);
731     CHECK_RETURN((status == napi_ok), "invalid value object", status);
732     napi_value vType = nullptr;
733     napi_create_int32(env, in.value[0], &vType);
734     napi_set_named_property(env, value, "type", vType);
735 
736     napi_value vValue = nullptr;
737     if (hasSchema) {
738         status = SetValue(env, in.value.ToString(), vValue);
739     } else {
740         status = SetValue(env, Blob2VariantValue(in.value), vValue);
741     }
742     CHECK_RETURN((status == napi_ok), "invalid entry value", status);
743     napi_set_named_property(env, value, "value", vValue);
744 
745     napi_set_named_property(env, out, "value", value);
746     return status;
747 }
748 
749 /* napi_value <-> std::list<DistributedKv::Entry> */
GetValue(napi_env env,napi_value in,std::list<DistributedKv::Entry> & out,bool hasSchema)750 napi_status JSUtil::GetValue(napi_env env, napi_value in, std::list<DistributedKv::Entry>& out, bool hasSchema)
751 {
752     ZLOGD("napi_value -> std::list<DistributedKv::Entry> ");
753     bool isArray = false;
754     napi_is_array(env, in, &isArray);
755     CHECK_RETURN(isArray, "not array", napi_invalid_arg);
756 
757     uint32_t length = 0;
758     napi_status status = napi_get_array_length(env, in, &length);
759     CHECK_RETURN((status == napi_ok) && (length > 0), "get_array failed!", status);
760     for (uint32_t i = 0; i < length; ++i) {
761         napi_value item = nullptr;
762         status = napi_get_element(env, in, i, &item);
763         CHECK_RETURN((status == napi_ok), "no element", status);
764         if ((status != napi_ok) || (item == nullptr)) {
765             continue;
766         }
767         DistributedKv::Entry entry;
768         status = GetValue(env, item, entry, hasSchema);
769         out.push_back(entry);
770     }
771     return status;
772 }
773 
SetValue(napi_env env,const std::list<DistributedKv::Entry> & in,napi_value & out,bool hasSchema)774 napi_status JSUtil::SetValue(napi_env env, const std::list<DistributedKv::Entry>& in, napi_value& out, bool hasSchema)
775 {
776     ZLOGD("napi_value <- std::list<DistributedKv::Entry> %{public}d", static_cast<int>(in.size()));
777     napi_status status = napi_create_array_with_length(env, in.size(), &out);
778     CHECK_RETURN(status == napi_ok, "create array failed!", status);
779     int index = 0;
780     for (const auto& item : in) {
781         napi_value entry = nullptr;
782         SetValue(env, item, entry, hasSchema);
783         napi_set_element(env, out, index++, entry);
784     }
785     return status;
786 }
787 
GetValue(napi_env env,napi_value jsValue,ValueObject::Type & valueObject)788 napi_status JSUtil::GetValue(napi_env env, napi_value jsValue, ValueObject::Type &valueObject)
789 {
790     napi_valuetype type = napi_undefined;
791     napi_typeof(env, jsValue, &type);
792     if (type == napi_string) {
793         std::string value;
794         JSUtil::GetValue(env, jsValue, value);
795         valueObject = value;
796     } else if (type == napi_number) {
797         double value = 0.0;
798         napi_get_value_double(env, jsValue, &value);
799         valueObject = value;
800     } else if (type == napi_boolean) {
801         bool value = false;
802         napi_get_value_bool(env, jsValue, &value);
803         valueObject = value;
804     } else if (type == napi_object) {
805         std::vector<uint8_t> value;
806         JSUtil::GetValue(env, jsValue, value);
807         valueObject = std::move(value);
808     }
809     return napi_ok;
810 }
GetValue(napi_env env,napi_value in,std::vector<DistributedKv::Entry> & out,bool hasSchema)811 napi_status JSUtil::GetValue(napi_env env, napi_value in, std::vector<DistributedKv::Entry> &out, bool hasSchema)
812 {
813     out.clear();
814     ZLOGD("napi_value -> std::vector<DistributedKv::Entry> ");
815     bool isArray = false;
816     napi_is_array(env, in, &isArray);
817     CHECK_RETURN(isArray, "not array", napi_invalid_arg);
818 
819     uint32_t length = 0;
820     napi_status status = napi_get_array_length(env, in, &length);
821     CHECK_RETURN((status == napi_ok) && (length > 0), "get_array failed!", status);
822     for (uint32_t i = 0; i < length; ++i) {
823         napi_value item = nullptr;
824         status = napi_get_element(env, in, i, &item);
825         CHECK_RETURN((status == napi_ok), "no element", status);
826         if ((status != napi_ok) || (item == nullptr)) {
827             continue;
828         }
829         DistributedKv::Entry entry;
830         status = GetValue(env, item, entry, hasSchema);
831         out.push_back(entry);
832     }
833     return status;
834 }
835 
SetValue(napi_env env,const std::vector<DistributedKv::Entry> & in,napi_value & out,bool hasSchema)836 napi_status JSUtil::SetValue(napi_env env, const std::vector<DistributedKv::Entry>& in, napi_value& out, bool hasSchema)
837 {
838     ZLOGD("napi_value <- std::vector<DistributedKv::Entry> %{public}d", static_cast<int>(in.size()));
839     napi_status status = napi_create_array_with_length(env, in.size(), &out);
840     CHECK_RETURN(status == napi_ok, "create array failed!", status);
841     int index = 0;
842     for (const auto& item : in) {
843         napi_value entry = nullptr;
844         SetValue(env, item, entry, hasSchema);
845         napi_set_element(env, out, index++, entry);
846     }
847     return status;
848 }
849 
850 /* napi_value <-> std::vector<DistributedKv::StoreId> */
GetValue(napi_env env,napi_value in,std::vector<DistributedKv::StoreId> & out)851 napi_status JSUtil::GetValue(napi_env env, napi_value in, std::vector<DistributedKv::StoreId>& out)
852 {
853     out.clear();
854     ZLOGD("napi_value -> std::vector<DistributedKv::StoreId> ");
855     bool isArray = false;
856     napi_is_array(env, in, &isArray);
857     CHECK_RETURN(isArray, "not array", napi_invalid_arg);
858 
859     uint32_t length = 0;
860     napi_status status = napi_get_array_length(env, in, &length);
861     CHECK_RETURN((status == napi_ok) && (length > 0), "get_array failed!", status);
862     for (uint32_t i = 0; i < length; ++i) {
863         napi_value item = nullptr;
864         status = napi_get_element(env, in, i, &item);
865         CHECK_RETURN((status == napi_ok), "no element", status);
866         if ((status != napi_ok) || (item == nullptr)) {
867             continue;
868         }
869         std::string value;
870         status = GetValue(env, item, value);
871         DistributedKv::StoreId storeId { value };
872         out.push_back(storeId);
873     }
874     return status;
875 }
876 
SetValue(napi_env env,const std::vector<DistributedKv::StoreId> & in,napi_value & out)877 napi_status JSUtil::SetValue(napi_env env, const std::vector<DistributedKv::StoreId>& in, napi_value& out)
878 {
879     ZLOGD("napi_value <- std::vector<DistributedKv::StoreId>  %{public}d", static_cast<int>(in.size()));
880     napi_status status = napi_create_array_with_length(env, in.size(), &out);
881     CHECK_RETURN((status == napi_ok), "create_array failed!", status);
882     int index = 0;
883     for (const auto& item : in) {
884         napi_value entry = nullptr;
885         SetValue(env, item.storeId, entry);
886         napi_set_element(env, out, index++, entry);
887     }
888     return status;
889 }
890 
891 /* napi_value <-> DistributedKv::ChangeNotification */
GetValue(napi_env env,napi_value in,DistributedKv::ChangeNotification & out,bool hasSchema)892 napi_status JSUtil::GetValue(napi_env env, napi_value in, DistributedKv::ChangeNotification& out, bool hasSchema)
893 {
894     ZLOGD("napi_value -> DistributedKv::ChangeNotification ");
895     (void)(env);
896     (void)(in);
897     (void)(out);
898     CHECK_RETURN(false, "DistributedKv::ChangeNotification from napi_value, unsupported!", napi_invalid_arg);
899     return napi_invalid_arg;
900 }
901 
SetValue(napi_env env,const DistributedKv::ChangeNotification & in,napi_value & out,bool hasSchema)902 napi_status JSUtil::SetValue(napi_env env, const DistributedKv::ChangeNotification& in, napi_value& out, bool hasSchema)
903 {
904     ZLOGD("napi_value <- DistributedKv::ChangeNotification ");
905     napi_status status = napi_create_object(env, &out);
906     CHECK_RETURN((status == napi_ok), "napi_create_object for DistributedKv::ChangeNotification failed!", status);
907     napi_value deviceId = nullptr;
908     status = SetValue(env, in.GetDeviceId(), deviceId);
909     CHECK_RETURN((status == napi_ok) || (deviceId == nullptr), "GetDeviceId failed!", status);
910     status = napi_set_named_property(env, out, "deviceId", deviceId);
911     CHECK_RETURN((status == napi_ok), "set_named_property deviceId failed!", status);
912 
913     napi_value insertEntries = nullptr;
914     status = SetValue(env, in.GetInsertEntries(), insertEntries, hasSchema);
915     CHECK_RETURN((status == napi_ok) || (insertEntries == nullptr), "GetInsertEntries failed!", status);
916     status = napi_set_named_property(env, out, "insertEntries", insertEntries);
917     CHECK_RETURN((status == napi_ok), "set_named_property insertEntries failed!", status);
918 
919     napi_value updateEntries = nullptr;
920     status = SetValue(env, in.GetUpdateEntries(), updateEntries, hasSchema);
921     CHECK_RETURN((status == napi_ok) || (updateEntries == nullptr), "GetUpdateEntries failed!", status);
922     status = napi_set_named_property(env, out, "updateEntries", updateEntries);
923     CHECK_RETURN((status == napi_ok), "set_named_property updateEntries failed!", status);
924 
925     napi_value deleteEntries = nullptr;
926     status = SetValue(env, in.GetDeleteEntries(), deleteEntries, hasSchema);
927     CHECK_RETURN((status == napi_ok) || (deleteEntries == nullptr), "GetDeleteEntries failed!", status);
928     status = napi_set_named_property(env, out, "deleteEntries", deleteEntries);
929     CHECK_RETURN((status == napi_ok), "set_named_property deleteEntries failed!", status);
930     return status;
931 }
932 
933 /* napi_value <-> DistributedKv::Options */
GetValue(napi_env env,napi_value in,DistributedKv::Options & options)934 napi_status JSUtil::GetValue(napi_env env, napi_value in, DistributedKv::Options& options)
935 {
936     ZLOGD("napi_value -> DistributedKv::Options ");
937     napi_status status = GetNamedProperty(env, in, "createIfMissing", options.createIfMissing, true);
938     CHECK_RETURN(status == napi_ok, "get createIfMissing param failed", napi_invalid_arg);
939     status = GetNamedProperty(env, in, "encrypt", options.encrypt, true);
940     CHECK_RETURN(status == napi_ok, "get encrypt param failed", napi_invalid_arg);
941     status = GetNamedProperty(env, in, "backup", options.backup, true);
942     CHECK_RETURN(status == napi_ok, "get backup param failed", napi_invalid_arg);
943     options.autoSync = false;
944     status = GetNamedProperty(env, in, "autoSync", options.autoSync, true);
945     CHECK_RETURN(status == napi_ok, "get autoSync param failed", napi_invalid_arg);
946 
947     int32_t kvStoreType = 0;
948     status = GetNamedProperty(env, in, "kvStoreType", kvStoreType, true);
949     CHECK_RETURN(status == napi_ok, "get kvStoreType param failed", napi_invalid_arg);
950     options.kvStoreType = static_cast<DistributedKv::KvStoreType>(kvStoreType);
951 
952     JsSchema *jsSchema = nullptr;
953     std::string strSchema;
954     status = GetNamedProperty(env, in, "schema", jsSchema, true);
955     CHECK_RETURN((status == napi_ok || GetNamedProperty(env, in, "schema", strSchema, true) == napi_ok),
956         "get schema param failed", napi_invalid_arg);
957     if (status == napi_ok && jsSchema != nullptr) {
958         options.schema = jsSchema->Dump();
959     }
960 
961     int32_t level = 0;
962     status = GetNamedProperty(env, in, "securityLevel", level, true);
963     CHECK_RETURN(status == napi_ok, "get securityLevel param failed", napi_invalid_arg);
964     options.securityLevel = level;
965     return napi_ok;
966 }
967 
GetValue(napi_env env,napi_value in,DistributedKv::UserInfo & userInfo)968 napi_status JSUtil::GetValue(napi_env env, napi_value in, DistributedKv::UserInfo& userInfo)
969 {
970     napi_status status = napi_ok;
971     status = GetNamedProperty(env, in, "userId", userInfo.userId, true);
972     return status != napi_ok ? status : GetNamedProperty(env, in, "userType", userInfo.userType, true);
973 }
974 
GetValue(napi_env env,napi_value inner,JsSchema * & out)975 napi_status JSUtil::GetValue(napi_env env, napi_value inner, JsSchema*& out)
976 {
977     return JsSchema::ToJson(env, inner, out);
978 }
979 
SetValue(napi_env env,const DistributedKv::Options & in,napi_value & out)980 napi_status JSUtil::SetValue(napi_env env, const DistributedKv::Options& in, napi_value& out)
981 {
982     (void)(env);
983     (void)(in);
984     (void)(out);
985     CHECK_RETURN(false, "DistributedKv::Options to napi_value, unsupported!", napi_invalid_arg);
986     return napi_invalid_arg;
987 }
988 
DefineClass(napi_env env,const std::string & name,const napi_property_descriptor * properties,size_t count,napi_callback newcb)989 napi_value JSUtil::DefineClass(napi_env env, const std::string& name,
990     const napi_property_descriptor* properties, size_t count, napi_callback newcb)
991 {
992     // base64("data.distributeddata") as rootPropName, i.e. global.<root>
993     const std::string rootPropName = "ZGF0YS5kaXN0cmlidXRlZGRhdGE";
994     napi_value root = nullptr;
995     bool hasRoot = false;
996     napi_value global = nullptr;
997     napi_get_global(env, &global);
998     napi_has_named_property(env, global, rootPropName.c_str(), &hasRoot);
999     if (hasRoot) {
1000         napi_get_named_property(env, global, rootPropName.c_str(), &root);
1001     } else {
1002         napi_create_object(env, &root);
1003         napi_set_named_property(env, global, rootPropName.c_str(), root);
1004     }
1005 
1006     std::string propName = "constructor_of_" + name;
1007     napi_value constructor = nullptr;
1008     bool hasProp = false;
1009     napi_has_named_property(env, root, propName.c_str(), &hasProp);
1010     if (hasProp) {
1011         napi_get_named_property(env, root, propName.c_str(), &constructor);
1012         if (constructor != nullptr) {
1013             ZLOGD("got data.distributeddata.%{public}s as constructor", propName.c_str());
1014             return constructor;
1015         }
1016         hasProp = false; // no constructor.
1017     }
1018 
1019     NAPI_CALL(env, napi_define_class(env, name.c_str(), name.size(), newcb, nullptr, count, properties, &constructor));
1020     NAPI_ASSERT(env, constructor != nullptr, "napi_define_class failed!");
1021 
1022     if (!hasProp) {
1023         napi_set_named_property(env, root, propName.c_str(), constructor);
1024         ZLOGD("save constructor to data.distributeddata.%{public}s", propName.c_str());
1025     }
1026     return constructor;
1027 }
1028 
NewWithRef(napi_env env,size_t argc,napi_value * argv,void ** out,napi_value constructor)1029 napi_ref JSUtil::NewWithRef(napi_env env, size_t argc, napi_value* argv, void** out, napi_value constructor)
1030 {
1031     napi_value object = nullptr;
1032     napi_status status = napi_new_instance(env, constructor, argc, argv, &object);
1033     CHECK_RETURN(status == napi_ok, "napi_new_instance failed", nullptr);
1034     CHECK_RETURN(object != nullptr, "napi_new_instance failed", nullptr);
1035 
1036     status = napi_unwrap(env, object, out);
1037     CHECK_RETURN(status == napi_ok, "napi_unwrap failed", nullptr);
1038     CHECK_RETURN(out != nullptr, "napi_unwrap failed", nullptr);
1039 
1040     napi_ref ref = nullptr;
1041     status = napi_create_reference(env, object, 1, &ref);
1042     CHECK_RETURN(status == napi_ok, "napi_create_referenc!e failed", nullptr);
1043     CHECK_RETURN(ref != nullptr, "napi_create_referenc!e failed", nullptr);
1044     return ref;
1045 }
1046 
Unwrap(napi_env env,napi_value in,void ** out,napi_value constructor)1047 napi_status JSUtil::Unwrap(napi_env env, napi_value in, void** out, napi_value constructor)
1048 {
1049     if (constructor != nullptr) {
1050         bool isInstance = false;
1051         napi_instanceof(env, in, constructor, &isInstance);
1052         if (!isInstance) {
1053             ZLOGE("not a instance of *");
1054             return napi_invalid_arg;
1055         }
1056     }
1057     return napi_unwrap(env, in, out);
1058 }
1059 
Equals(napi_env env,napi_value value,napi_ref copy)1060 bool JSUtil::Equals(napi_env env, napi_value value, napi_ref copy)
1061 {
1062     if (copy == nullptr) {
1063         return (value == nullptr);
1064     }
1065 
1066     napi_value copyValue = nullptr;
1067     napi_get_reference_value(env, copy, &copyValue);
1068 
1069     bool isEquals = false;
1070     napi_strict_equals(env, value, copyValue, &isEquals);
1071     return isEquals;
1072 }
1073 
IsNull(napi_env env,napi_value value)1074 bool JSUtil::IsNull(napi_env env, napi_value value)
1075 {
1076     napi_valuetype type = napi_undefined;
1077     napi_status status = napi_typeof(env, value, &type);
1078     if (status == napi_ok && (type == napi_undefined || type == napi_null)) {
1079         return true;
1080     }
1081     return false;
1082 }
1083 
GetValue(napi_env env,napi_value in,DataQuery & query)1084 napi_status JSUtil::GetValue(napi_env env, napi_value in, DataQuery &query)
1085 {
1086     ZLOGD("napi_value -> std::GetValue DataQuery");
1087     napi_valuetype type = napi_undefined;
1088     napi_status nstatus = napi_typeof(env, in, &type);
1089     CHECK_RETURN((nstatus == napi_ok) && (type == napi_object), "invalid type", napi_invalid_arg);
1090     PredicatesProxy *predicates = nullptr;
1091     napi_unwrap(env, in, reinterpret_cast<void **>(&predicates));
1092     CHECK_RETURN((predicates != nullptr), "invalid type", napi_invalid_arg);
1093     Status status = KvUtils::ToQuery(*(predicates->predicates_), query);
1094     if (status != Status::SUCCESS) {
1095         ZLOGD("napi_value -> GetValue DataQuery failed ");
1096     }
1097     return nstatus;
1098 }
1099 
GetCurrentAbilityParam(napi_env env,ContextParam & param)1100 napi_status JSUtil::GetCurrentAbilityParam(napi_env env, ContextParam &param)
1101 {
1102     auto ability = AbilityRuntime::GetCurrentAbility(env);
1103     if (ability == nullptr) {
1104         ZLOGE("GetCurrentAbility -> ability pointer is nullptr");
1105         return napi_invalid_arg;
1106     }
1107 
1108     auto context = ability->GetAbilityContext();
1109     if (context == nullptr) {
1110         ZLOGE("Get fa context  -> fa context pointer is nullptr");
1111         return napi_invalid_arg;
1112     }
1113     param.area = context->GetArea();
1114     param.baseDir = context->GetDatabaseDir();
1115     auto hapInfo = context->GetHapModuleInfo();
1116     if (hapInfo != nullptr) {
1117         param.hapName = hapInfo->moduleName;
1118     }
1119     ZLOGI("area:%{public}d hapName:%{public}s baseDir:%{public}s", param.area, param.hapName.c_str(),
1120         param.baseDir.c_str());
1121     return napi_ok;
1122 }
1123 
GetValue(napi_env env,napi_value in,ContextParam & param)1124 napi_status JSUtil::GetValue(napi_env env, napi_value in, ContextParam &param)
1125 {
1126     if (in == nullptr) {
1127         ZLOGD("hasProp is false -> fa stage");
1128         return GetCurrentAbilityParam(env, param);
1129     }
1130 
1131     bool isStageMode = false;
1132     napi_status status = GetNamedProperty(env, in, "stageMode", isStageMode);
1133     CHECK_RETURN(status == napi_ok, "get stageMode param failed", napi_invalid_arg);
1134     if (!isStageMode) {
1135         ZLOGD("isStageMode is false -> fa stage");
1136         return GetCurrentAbilityParam(env, param);
1137     }
1138 
1139     ZLOGD("stage mode branch");
1140     status = GetNamedProperty(env, in, "databaseDir", param.baseDir);
1141     CHECK_RETURN(status == napi_ok, "get databaseDir param failed", napi_invalid_arg);
1142     status = GetNamedProperty(env, in, "area", param.area);
1143     CHECK_RETURN(status == napi_ok, "get area param failed", napi_invalid_arg);
1144     napi_value hapInfo = nullptr;
1145     GetNamedProperty(env, in, "currentHapModuleInfo", hapInfo);
1146     if (hapInfo != nullptr) {
1147         status = GetNamedProperty(env, hapInfo, "name", param.hapName);
1148         CHECK_RETURN(status == napi_ok, "get hap name failed", napi_invalid_arg);
1149     }
1150     return napi_ok;
1151 }
1152 
GetInnerValue(napi_env env,napi_value in,const std::string & prop,bool optional)1153 std::pair<napi_status, napi_value> JSUtil::GetInnerValue(
1154     napi_env env, napi_value in, const std::string& prop, bool optional)
1155 {
1156     bool hasProp = false;
1157     napi_status status = napi_has_named_property(env, in, prop.c_str(), &hasProp);
1158     if (status != napi_ok) {
1159         return std::make_pair(napi_generic_failure, nullptr);
1160     }
1161     if (!hasProp) {
1162         status = optional ? napi_ok : napi_generic_failure;
1163         return std::make_pair(status, nullptr);
1164     }
1165     napi_value inner = nullptr;
1166     status = napi_get_named_property(env, in, prop.c_str(), &inner);
1167     if (status != napi_ok || inner == nullptr) {
1168         return std::make_pair(napi_generic_failure, nullptr);
1169     }
1170     if (optional && JSUtil::IsNull(env, inner)) {
1171         return std::make_pair(napi_ok, nullptr);
1172     }
1173     return std::make_pair(napi_ok, inner);
1174 }
1175 } // namespace OHOS::DistributedData
1176