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