1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "js_common_utils.h"
17 #include <cstdint>
18 #include <tuple>
19 #include <utility>
20 #include "hilog/log_c.h"
21 #include "js_native_api.h"
22 #include "js_native_api_types.h"
23 #include "log_print.h"
24 
25 namespace OHOS {
26 namespace PreferencesJsKit {
27 using namespace OHOS::NativePreferences;
Convert2NativeValue(napi_env env,napi_value jsValue,std::string & output)28 int32_t JSUtils::Convert2NativeValue(napi_env env, napi_value jsValue, std::string &output)
29 {
30     size_t bufferSize = 0;
31     napi_status status = napi_get_value_string_utf8(env, jsValue, nullptr, 0, &bufferSize);
32     if (status != napi_ok) {
33         LOG_DEBUG("get std::string failed, status = %{public}d", status);
34         return NAPI_TYPE_ERROR;
35     }
36     if (bufferSize > MAX_VALUE_LENGTH) {
37         LOG_ERROR("string  must be less than the limit length.");
38         return EXCEED_MAX_LENGTH;
39     }
40     char *buffer = (char *)malloc(bufferSize + 1);
41     if (buffer == nullptr) {
42         LOG_ERROR("malloc failed, buffer is nullptr.");
43         return ERR;
44     }
45     status = napi_get_value_string_utf8(env, jsValue, buffer, bufferSize + 1, &bufferSize);
46     if (status != napi_ok) {
47         free(buffer);
48         LOG_DEBUG("JSUtils::Convert2NativeValue get jsVal failed, status = %{public}d", status);
49         return status;
50     }
51     output = buffer;
52     free(buffer);
53     return napi_ok;
54 }
55 
Convert2NativeValue(napi_env env,napi_value jsValue,bool & output)56 int32_t JSUtils::Convert2NativeValue(napi_env env, napi_value jsValue, bool &output)
57 {
58     bool bValue = false;
59     napi_status status = napi_get_value_bool(env, jsValue, &bValue);
60     if (status != napi_ok) {
61         LOG_DEBUG("get bool failed, status = %{public}d", status);
62         return NAPI_TYPE_ERROR;
63     }
64     output = bValue;
65     return napi_ok;
66 }
67 
Convert2NativeValue(napi_env env,napi_value jsValue,double & output)68 int32_t JSUtils::Convert2NativeValue(napi_env env, napi_value jsValue, double &output)
69 {
70     double number = 0.0;
71     napi_status status = napi_get_value_double(env, jsValue, &number);
72     if (status != napi_ok) {
73         LOG_DEBUG("get double failed, status = %{public}d", status);
74         return NAPI_TYPE_ERROR;
75     }
76     output = number;
77     return napi_ok;
78 }
79 
Convert2NativeValue(napi_env env,napi_value jsValue,float & output)80 int32_t JSUtils::Convert2NativeValue(napi_env env, napi_value jsValue, float &output)
81 {
82     LOG_DEBUG("Convert2NativeValue js just support double data not support float");
83     return NAPI_TYPE_ERROR;
84 }
85 
Convert2NativeValue(napi_env env,napi_value jsValue,int32_t & output)86 int32_t JSUtils::Convert2NativeValue(napi_env env, napi_value jsValue, int32_t &output)
87 {
88     LOG_DEBUG("Convert2NativeValue js just support double data not support int32_t");
89     return NAPI_TYPE_ERROR;
90 }
91 
Convert2NativeValue(napi_env env,napi_value jsValue,int64_t & output)92 int32_t JSUtils::Convert2NativeValue(napi_env env, napi_value jsValue, int64_t &output)
93 {
94     LOG_DEBUG("Convert2NativeValue js just support double data not support int64_t");
95     return NAPI_TYPE_ERROR;
96 }
97 
Convert2NativeValue(napi_env env,napi_value jsValue,std::vector<uint8_t> & output)98 int32_t JSUtils::Convert2NativeValue(napi_env env, napi_value jsValue, std::vector<uint8_t> &output)
99 {
100     bool isTypedarray = false;
101     napi_status result = napi_is_typedarray(env, jsValue, &isTypedarray);
102     if (result != napi_ok || !isTypedarray) {
103         LOG_DEBUG("napi_is_typedarray fail. result %{public}d isTypedarray %{public}d", result, isTypedarray);
104         return NAPI_TYPE_ERROR;
105     }
106     napi_typedarray_type type = napi_uint8_array;
107     size_t length = 0;
108     void *data = nullptr;
109     result = napi_get_typedarray_info(env, jsValue, &type, &length, &data, nullptr, nullptr);
110     if (result != napi_ok) {
111         LOG_ERROR("napi_get_typedarray_info fail");
112         return result;
113     }
114     if (type != napi_uint8_array) {
115         LOG_ERROR("value is not napi_uint8_array");
116         return NAPI_TYPE_ERROR;
117     }
118     if (length > MAX_VALUE_LENGTH) {
119         LOG_ERROR("unit8Array must be less than the limit length.");
120         return EXCEED_MAX_LENGTH;
121     }
122     output.clear();
123     if (length > 0) {
124         output.resize(length);
125         output.assign(static_cast<uint8_t*>(data), static_cast<uint8_t*>(data) + length);
126     }
127     return napi_ok;
128 }
129 
Convert2NativeValue(napi_env env,napi_value jsValue,Object & output)130 int32_t JSUtils::Convert2NativeValue(napi_env env, napi_value jsValue, Object &output)
131 {
132     if (GetValueType(env, jsValue) != napi_object) {
133         LOG_DEBUG("Not of object type.");
134         return NAPI_TYPE_ERROR;
135     }
136     auto [status, jsonStr] = JsonStringify(env, jsValue);
137     if (status != napi_ok) {
138         LOG_ERROR("json stringify failed.");
139         return status;
140     }
141     return Convert2NativeValue(env, jsonStr, output.valueStr);
142 }
143 
Convert2NativeValue(napi_env env,napi_value jsValue,BigInt & output)144 int32_t JSUtils::Convert2NativeValue(napi_env env, napi_value jsValue, BigInt &output)
145 {
146     if (GetValueType(env, jsValue) != napi_bigint) {
147         LOG_DEBUG("Not of bigint type.");
148         return NAPI_TYPE_ERROR;
149     }
150     size_t wordCount = 0;
151     napi_status status = napi_get_value_bigint_words(env, jsValue, nullptr, &wordCount, nullptr);
152     if (status != napi_ok || wordCount == 0) {
153         LOG_ERROR("get wordCount failed %{public}d wordCount %{public}zu.", status, wordCount);
154         return status;
155     }
156     output.words_.resize(wordCount);
157     status = napi_get_value_bigint_words(env, jsValue, &output.sign_, &wordCount, output.words_.data());
158     if (status != napi_ok) {
159         LOG_ERROR("napi_get_value_bigint_words failed %{public}d wordCount %{public}zu.", status, wordCount);
160         return status;
161     }
162     return napi_ok;
163 }
164 
Convert2NativeValue(napi_env env,napi_value jsValue,std::monostate & value)165 int32_t JSUtils::Convert2NativeValue(napi_env env, napi_value jsValue, std::monostate &value)
166 {
167     return NAPI_TYPE_ERROR;
168 }
169 
Equals(napi_env env,napi_value value,napi_ref copy)170 bool JSUtils::Equals(napi_env env, napi_value value, napi_ref copy)
171 {
172     if (copy == nullptr || env == nullptr) {
173         return (value == nullptr);
174     }
175 
176     napi_value copyValue = nullptr;
177     napi_get_reference_value(env, copy, &copyValue);
178 
179     bool isEquals = false;
180     napi_strict_equals(env, value, copyValue, &isEquals);
181     return isEquals;
182 }
183 
Convert2JSValue(napi_env env,int32_t value)184 napi_value JSUtils::Convert2JSValue(napi_env env, int32_t value)
185 {
186     napi_value jsValue;
187     if (napi_create_int32(env, value, &jsValue) != napi_ok) {
188         LOG_DEBUG("Convert int32_t failed");
189         return nullptr;
190     }
191     return jsValue;
192 }
193 
Convert2JSValue(napi_env env,uint32_t value)194 napi_value JSUtils::Convert2JSValue(napi_env env, uint32_t value)
195 {
196     napi_value jsValue;
197     if (napi_create_uint32(env, value, &jsValue) != napi_ok) {
198         LOG_DEBUG("Convert uint32_t failed");
199         return nullptr;
200     }
201     return jsValue;
202 }
203 
Convert2JSValue(napi_env env,int64_t value)204 napi_value JSUtils::Convert2JSValue(napi_env env, int64_t value)
205 {
206     napi_value jsValue;
207     if (napi_create_int64(env, value, &jsValue) != napi_ok) {
208         LOG_DEBUG("Convert int64_t failed");
209         return nullptr;
210     }
211     return jsValue;
212 }
213 
Convert2JSValue(napi_env env,bool value)214 napi_value JSUtils::Convert2JSValue(napi_env env, bool value)
215 {
216     napi_value jsValue;
217     if (napi_get_boolean(env, value, &jsValue) != napi_ok) {
218         LOG_DEBUG("Convert bool failed");
219         return nullptr;
220     }
221     return jsValue;
222 }
223 
Convert2JSValue(napi_env env,double value)224 napi_value JSUtils::Convert2JSValue(napi_env env, double value)
225 {
226     napi_value jsValue;
227     if (napi_create_double(env, value, &jsValue) != napi_ok) {
228         LOG_DEBUG("Convert double failed");
229         return nullptr;
230     }
231     return jsValue;
232 }
233 
Convert2JSValue(napi_env env,float value)234 napi_value JSUtils::Convert2JSValue(napi_env env, float value)
235 {
236     napi_value jsValue;
237     if (napi_create_double(env, value, &jsValue) != napi_ok) {
238         LOG_DEBUG("Convert float failed");
239         return nullptr;
240     }
241     return jsValue;
242 }
243 
Convert2JSValue(napi_env env,const std::vector<uint8_t> & value)244 napi_value JSUtils::Convert2JSValue(napi_env env, const std::vector<uint8_t> &value)
245 {
246     size_t size = value.size();
247     void *data = nullptr;
248     napi_value buffer = nullptr;
249     napi_status ret = napi_create_arraybuffer(env, size, &data, &buffer);
250     if (ret != napi_ok) {
251         LOG_ERROR("napi_create_arraybuffer failed %{public}d", ret);
252         return nullptr;
253     }
254     if (size != 0) {
255         std::copy(value.begin(), value.end(), static_cast<uint8_t*>(data));
256     }
257     napi_value napiValue = nullptr;
258     ret = napi_create_typedarray(env, napi_uint8_array, size, buffer, 0, &napiValue);
259     if (ret != napi_ok) {
260         LOG_ERROR("napi_create_typedarray failed %{public}d", ret);
261         return nullptr;
262     }
263     return napiValue;
264 }
265 
Convert2JSValue(napi_env env,const Object & value)266 napi_value JSUtils::Convert2JSValue(napi_env env, const Object &value)
267 {
268     napi_value jsValue = JsonParse(env, value.valueStr);
269     if (jsValue == nullptr) {
270         LOG_ERROR("Convert object failed");
271     }
272     return jsValue;
273 }
274 
Convert2JSValue(napi_env env,const std::string & value)275 napi_value JSUtils::Convert2JSValue(napi_env env, const std::string &value)
276 {
277     napi_value jsValue = nullptr;
278     if (napi_create_string_utf8(env, value.c_str(), value.size(), &jsValue) != napi_ok) {
279         LOG_DEBUG("Convert std::string failed");
280         return nullptr;
281     }
282     return jsValue;
283 }
284 
Convert2JSValue(napi_env env,const BigInt & value)285 napi_value JSUtils::Convert2JSValue(napi_env env, const BigInt &value)
286 {
287     napi_value bigint = nullptr;
288     napi_status status = napi_create_bigint_words(env, value.sign_, value.words_.size(), value.words_.data(), &bigint);
289     if (status != napi_ok || bigint == nullptr) {
290         LOG_ERROR("napi_create_bigint_words failed %{public}d", status);
291         return nullptr;
292     }
293     return bigint;
294 }
295 
Convert2JSValue(napi_env env,const std::monostate & value)296 napi_value JSUtils::Convert2JSValue(napi_env env, const std::monostate &value)
297 {
298     napi_value result = nullptr;
299     napi_get_null(env, &result);
300     return result;
301 }
302 
GetValueType(napi_env env,napi_value value)303 napi_valuetype JSUtils::GetValueType(napi_env env, napi_value value)
304 {
305     napi_valuetype valueType = napi_undefined;
306     napi_typeof(env, value, &valueType);
307     return valueType;
308 }
309 
JsonStringify(napi_env env,napi_value value)310 std::tuple<napi_status, napi_value> JSUtils::JsonStringify(napi_env env, napi_value value)
311 {
312     napi_value global = nullptr;
313     napi_status status = napi_get_global(env, &global);
314     PRE_CHECK_RETURN_CORE(status == napi_ok, PRE_REVT_NOTHING, std::make_tuple(status, nullptr));
315     napi_value json = nullptr;
316     status = napi_get_named_property(env, global, GLOBAL_JSON, &json);
317     PRE_CHECK_RETURN_CORE(status == napi_ok, PRE_REVT_NOTHING, std::make_tuple(status, nullptr));
318     napi_value stringify = nullptr;
319     status = napi_get_named_property(env, json, GLOBAL_STRINGIFY, &stringify);
320     PRE_CHECK_RETURN_CORE(status == napi_ok, PRE_REVT_NOTHING, std::make_tuple(status, nullptr));
321     napi_value res = nullptr;
322     napi_value argv[1] = {value};
323     status = napi_call_function(env, json, stringify, 1, argv, &res);
324     PRE_CHECK_RETURN_CORE(status == napi_ok, PRE_REVT_NOTHING, std::make_tuple(status, nullptr));
325     return std::make_tuple(napi_ok, res);
326 }
327 
JsonParse(napi_env env,const std::string & inStr,bool sendable)328 napi_value JSUtils::JsonParse(napi_env env, const std::string &inStr, bool sendable)
329 {
330     if (inStr.empty()) {
331         LOG_ERROR("JsonParse failed, inStr is empty");
332         return nullptr;
333     }
334     napi_value jsValue = Convert2JSValue(env, inStr);
335     napi_value global = nullptr;
336     PRE_CHECK_RETURN_CORE(napi_get_global(env, &global) == napi_ok, PRE_REVT_NOTHING, nullptr);
337     napi_value json = nullptr;
338     PRE_CHECK_RETURN_CORE(
339         napi_get_named_property(env, global, GLOBAL_JSON, &json) == napi_ok, PRE_REVT_NOTHING, nullptr);
340     napi_value parse = nullptr;
341     PRE_CHECK_RETURN_CORE(
342         napi_get_named_property(env, json, sendable ? GLOBAL_PARSE_SENDABLE : GLOBAL_PARSE, &parse) == napi_ok,
343         PRE_REVT_NOTHING, nullptr);
344     if (GetValueType(env, parse) != napi_function) {
345         LOG_ERROR("Get parse func failed");
346         return nullptr;
347     }
348     napi_value res = nullptr;
349     napi_value argv[1] = { jsValue };
350     PRE_CHECK_RETURN_CORE(napi_call_function(env, json, parse, 1, argv, &res) == napi_ok, PRE_REVT_NOTHING, nullptr);
351     return res;
352 }
353 
354 } // namespace PreferencesJsKit
355 } // namespace OHOS
356