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, ©Value);
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