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 #include "js_util.h"
16 
17 #include <endian.h>
18 #include <securec.h>
19 
20 #include "logger.h"
21 #include "common_types.h"
22 
23 namespace OHOS::ObjectStore {
24 constexpr int32_t STR_MAX_LENGTH = 4096;
25 constexpr size_t STR_TAIL_LENGTH = 1;
26 
27 /* napi_value <-> bool */
GetValue(napi_env env,napi_value in,bool & out)28 napi_status JSUtil::GetValue(napi_env env, napi_value in, bool &out)
29 {
30     LOG_DEBUG("napi_value <- bool");
31     return napi_get_value_bool(env, in, &out);
32 }
33 
SetValue(napi_env env,const bool & in,napi_value & out)34 napi_status JSUtil::SetValue(napi_env env, const bool &in, napi_value &out)
35 {
36     LOG_DEBUG("napi_value -> bool");
37     return napi_get_boolean(env, in, &out);
38 }
39 
40 /* napi_value <-> double */
GetValue(napi_env env,napi_value in,double & out)41 napi_status JSUtil::GetValue(napi_env env, napi_value in, double &out)
42 {
43     LOG_DEBUG("napi_value -> double");
44     return napi_get_value_double(env, in, &out);
45 }
46 
SetValue(napi_env env,const double & in,napi_value & out)47 napi_status JSUtil::SetValue(napi_env env, const double &in, napi_value &out)
48 {
49     LOG_DEBUG("napi_value <- double");
50     return napi_create_double(env, in, &out);
51 }
52 
53 /* napi_value <-> int64_t */
GetValue(napi_env env,napi_value in,int64_t & out)54 napi_status JSUtil::GetValue(napi_env env, napi_value in, int64_t& out)
55 {
56     return napi_get_value_int64(env, in, &out);
57 }
58 
SetValue(napi_env env,const int64_t & in,napi_value & out)59 napi_status JSUtil::SetValue(napi_env env, const int64_t& in, napi_value& out)
60 {
61     return napi_create_int64(env, in, &out);
62 }
63 
64 /* napi_value <-> uint32_t */
GetValue(napi_env env,napi_value in,uint32_t & out)65 napi_status JSUtil::GetValue(napi_env env, napi_value in, uint32_t& out)
66 {
67     return napi_get_value_uint32(env, in, &out);
68 }
69 
SetValue(napi_env env,const uint32_t & in,napi_value & out)70 napi_status JSUtil::SetValue(napi_env env, const uint32_t& in, napi_value& out)
71 {
72     return napi_create_uint32(env, in, &out);
73 }
74 
75 /* napi_value <-> std::string */
GetValue(napi_env env,napi_value in,std::string & out)76 napi_status JSUtil::GetValue(napi_env env, napi_value in, std::string &out)
77 {
78     size_t maxLen = STR_MAX_LENGTH;
79     napi_status status = napi_get_value_string_utf8(env, in, NULL, 0, &maxLen);
80     if (status != napi_ok || maxLen <= 0) {
81         return napi_generic_failure;
82     }
83     char *buf = new (std::nothrow) char[maxLen + STR_TAIL_LENGTH];
84     if (buf != nullptr) {
85         size_t len = 0;
86         status = napi_get_value_string_utf8(env, in, buf, maxLen + STR_TAIL_LENGTH, &len);
87         if (status == napi_ok) {
88             out = std::string(buf);
89         }
90         delete[] buf;
91     } else {
92         status = napi_generic_failure;
93     }
94     return status;
95 }
96 
SetValue(napi_env env,const std::string & in,napi_value & out)97 napi_status JSUtil::SetValue(napi_env env, const std::string &in, napi_value &out)
98 {
99     LOG_DEBUG("napi_value <- std::string %{public}d", (int)in.length());
100     return napi_create_string_utf8(env, in.c_str(), in.size(), &out);
101 }
102 
103 /* napi_value <-> std::vector<std::string> */
GetValue(napi_env env,napi_value in,std::vector<std::string> & out)104 napi_status JSUtil::GetValue(napi_env env, napi_value in, std::vector<std::string> &out)
105 {
106     LOG_DEBUG("napi_value -> std::vector<std::string>");
107     bool isArray = false;
108     napi_is_array(env, in, &isArray);
109     LOG_ERROR_RETURN(isArray, "not an array", napi_invalid_arg);
110 
111     uint32_t length = 0;
112     napi_status status = napi_get_array_length(env, in, &length);
113     LOG_ERROR_RETURN((status == napi_ok) && (length > 0), "get_array failed!", napi_invalid_arg);
114     for (uint32_t i = 0; i < length; ++i) {
115         napi_value item = nullptr;
116         status = napi_get_element(env, in, i, &item);
117         LOG_ERROR_RETURN((item != nullptr) && (status == napi_ok), "no element", napi_invalid_arg);
118         std::string value;
119         status = GetValue(env, item, value);
120         LOG_ERROR_RETURN(status == napi_ok, "not a string", napi_invalid_arg);
121         out.push_back(value);
122     }
123     return status;
124 }
125 
SetValue(napi_env env,const std::vector<std::string> & in,napi_value & out)126 napi_status JSUtil::SetValue(napi_env env, const std::vector<std::string> &in, napi_value &out)
127 {
128     LOG_DEBUG("napi_value <- std::vector<std::string>");
129     napi_status status = napi_create_array_with_length(env, in.size(), &out);
130     LOG_ERROR_RETURN(status == napi_ok, "create array failed!", status);
131     int index = 0;
132     for (auto &item : in) {
133         napi_value element = nullptr;
134         SetValue(env, item, element);
135         status = napi_set_element(env, out, index++, element);
136         LOG_ERROR_RETURN((status == napi_ok), "napi_set_element failed!", status);
137     }
138     return status;
139 }
140 
141 /* napi_value <-> std::vector<uint8_t> */
GetValue(napi_env env,napi_value in,std::vector<uint8_t> & out)142 napi_status JSUtil::GetValue(napi_env env, napi_value in, std::vector<uint8_t> &out)
143 {
144     out.clear();
145     LOG_DEBUG("napi_value -> std::vector<uint8_t> ");
146     napi_typedarray_type type = napi_biguint64_array;
147     size_t length = 0;
148     napi_value buffer = nullptr;
149     size_t offset = 0;
150     void *data = nullptr;
151     napi_status status = napi_get_typedarray_info(env, in, &type, &length, &data, &buffer, &offset);
152     LOG_DEBUG("array type=%{public}d length=%{public}d offset=%{public}d  status=%{public}d", (int)type, (int)length,
153         (int)offset, status);
154     LOG_ERROR_RETURN(status == napi_ok, "napi_get_typedarray_info failed!", napi_invalid_arg);
155     LOG_ERROR_RETURN(type == napi_uint8_array, "is not Uint8Array!", napi_invalid_arg);
156     LOG_ERROR_RETURN((length > 0) && (data != nullptr), "invalid data!", napi_invalid_arg);
157     out.assign(static_cast<uint8_t *>(data), static_cast<uint8_t *>(data) + length);
158     return status;
159 }
160 
SetValue(napi_env env,const std::vector<uint8_t> & in,napi_value & out)161 napi_status JSUtil::SetValue(napi_env env, const std::vector<uint8_t> &in, napi_value &out)
162 {
163     LOG_DEBUG("napi_value <- std::vector<uint8_t> ");
164     LOG_ERROR_RETURN(in.size() > 0, "invalid std::vector<uint8_t>", napi_invalid_arg);
165     void *data = nullptr;
166     napi_value buffer = nullptr;
167     napi_status status = napi_create_arraybuffer(env, in.size(), &data, &buffer);
168     LOG_ERROR_RETURN((status == napi_ok), "create array buffer failed!", status);
169 
170     if (memcpy_s(data, in.size(), in.data(), in.size()) != EOK) {
171         LOG_ERROR("memcpy_s not EOK");
172         return napi_invalid_arg;
173     }
174     status = napi_create_typedarray(env, napi_uint8_array, in.size(), buffer, 0, &out);
175     LOG_ERROR_RETURN((status == napi_ok), "napi_value <- std::vector<uint8_t> invalid value", status);
176     return status;
177 }
178 
GetValue(napi_env env,napi_value in,AssetBindInfo & bindInfo)179 napi_status JSUtil::GetValue(napi_env env, napi_value in, AssetBindInfo &bindInfo)
180 {
181     napi_status status = napi_invalid_arg;
182     status = GetNamedProperty(env, in, "storeName", bindInfo.storeName);
183     LOG_ERROR_RETURN(status == napi_ok, "get store param failed", status);
184     status = GetNamedProperty(env, in, "tableName", bindInfo.tableName);
185     LOG_ERROR_RETURN(status == napi_ok, "get table param failed", status);
186     status = GetNamedProperty(env, in, "primaryKey", bindInfo.primaryKey);
187 
188     LOG_ERROR_RETURN(status == napi_ok, "get primary param failed", status);
189     status = GetNamedProperty(env, in, "field", bindInfo.field);
190     LOG_ERROR_RETURN(status == napi_ok, "get field param failed", status);
191     status = GetNamedProperty(env, in, "assetName", bindInfo.assetName);
192     LOG_ERROR_RETURN(status == napi_ok, "get assetName param failed", status);
193     return status;
194 }
195 
GetValue(napi_env env,napi_value in,Asset & asset)196 napi_status JSUtil::GetValue(napi_env env, napi_value in, Asset &asset)
197 {
198     napi_valuetype type;
199     napi_status status = napi_typeof(env, in, &type);
200     LOG_ERROR_RETURN((status == napi_ok) && (type == napi_object), "Asset type invalid", napi_invalid_arg);
201     status = GetNamedProperty(env, in, "name", asset.name);
202     LOG_ERROR_RETURN(status == napi_ok, "get name param failed", status);
203     status = GetNamedProperty(env, in, "uri", asset.uri);
204     LOG_ERROR_RETURN(status == napi_ok, "get uri param failed", status);
205     status = GetNamedProperty(env, in, "path", asset.path);
206     LOG_ERROR_RETURN(status == napi_ok, "get path param failed", status);
207     status = GetNamedProperty(env, in, "createTime", asset.createTime);
208     LOG_ERROR_RETURN(status == napi_ok, "get createTime param failed", status);
209     status = GetNamedProperty(env, in, "modifyTime", asset.modifyTime);
210     LOG_ERROR_RETURN(status == napi_ok, "get modifyTime param failed", status);
211     status = GetNamedProperty(env, in, "size", asset.size);
212     LOG_ERROR_RETURN(status == napi_ok, "get size param failed", status);
213     status = GetNamedProperty(env, in, "status", asset.status, true);
214     LOG_ERROR_RETURN(status == napi_ok, "get status param failed", status);
215     return status;
216 }
217 
GetValue(napi_env env,napi_value in,Assets & assets)218 napi_status JSUtil::GetValue(napi_env env, napi_value in, Assets &assets)
219 {
220     assets.clear();
221     bool isArray = false;
222     napi_is_array(env, in, &isArray);
223     LOG_ERROR_RETURN(isArray, "not an array", napi_generic_failure);
224 
225     uint32_t arrLen = 0;
226     napi_status status = napi_get_array_length(env, in, &arrLen);
227     LOG_ERROR_RETURN((status == napi_ok) && (arrLen > 0), "get_array failed!", status);
228     for (uint32_t i = 0; i < arrLen; ++i) {
229         napi_value item = nullptr;
230         status = napi_get_element(env, in, i, &item);
231         LOG_ERROR_RETURN((item != nullptr) && (status == napi_ok), "no element", status);
232         Asset asset;
233         status = GetValue(env, item, asset);
234         LOG_ERROR_RETURN(status == napi_ok, "not a asset object", status);
235         assets.push_back(asset);
236     }
237     return status;
238 }
239 
GetValue(napi_env env,napi_value in,ValuesBucket & out)240 napi_status JSUtil::GetValue(napi_env env, napi_value in, ValuesBucket &out)
241 {
242     out.clear();
243     napi_value values = nullptr;
244     uint32_t count = 0;
245     napi_get_all_property_names(env, in, napi_key_own_only,
246         static_cast<napi_key_filter>(napi_key_enumerable | napi_key_skip_symbols),
247         napi_key_numbers_to_strings, &values);
248     napi_status status = napi_get_array_length(env, values, &count);
249     LOG_ERROR_RETURN(status == napi_ok && count > 0, "get ValuesBucket failed", napi_invalid_arg);
250     napi_value key = nullptr;
251     napi_value val = nullptr;
252     for (uint32_t index = 0; index < count; index++) {
253         status = napi_get_element(env, values, index, &key);
254         LOG_ERROR_RETURN(status == napi_ok && key != nullptr, "no element", napi_invalid_arg);
255         std::string keyStr;
256         status = GetValue(env, key, keyStr);
257         LOG_ERROR_RETURN(status == napi_ok, "get key failed", status);
258         status = napi_get_property(env, in, key, &val);
259         LOG_ERROR_RETURN(status == napi_ok && val != nullptr, "no element", napi_invalid_arg);
260         ValueObject value;
261         status = GetValue(env, val, value);
262         if (status == napi_ok) {
263             out.insert(std::pair<std::string, ValueObject>(keyStr, value));
264         } else if (status != napi_generic_failure) {
265             LOG_ERROR("The value type %{public}s is invalid: ", keyStr.c_str());
266             return status;
267         }
268     }
269     return napi_ok;
270 }
271 
GetValue(napi_env env,napi_value jsValue,std::monostate & out)272 napi_status JSUtil::GetValue(napi_env env, napi_value jsValue, std::monostate &out)
273 {
274     napi_value tempValue;
275     napi_get_null(env, &tempValue);
276     bool equal = false;
277     napi_strict_equals(env, jsValue, tempValue, &equal);
278     if (equal) {
279         out = std::monostate();
280         return napi_ok;
281     }
282     LOG_DEBUG("jsValue is not null");
283     return napi_invalid_arg;
284 }
285 
IsNull(napi_env env,napi_value value)286 bool JSUtil::IsNull(napi_env env, napi_value value)
287 {
288     napi_valuetype type = napi_undefined;
289     napi_status status = napi_typeof(env, value, &type);
290     if (status == napi_ok && (type == napi_undefined || type == napi_null)) {
291         return true;
292     }
293     return false;
294 }
295 } // namespace OHOS::ObjectStore
296