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 #ifndef DISTRIBUTEDDATAMGR_APPDATAMGR_JSUTILS_H
17 #define DISTRIBUTEDDATAMGR_APPDATAMGR_JSUTILS_H
18 
19 #include <stdint.h>
20 
21 #include <functional>
22 #include <iostream>
23 #include <map>
24 #include <memory>
25 #include <optional>
26 #include <string>
27 #include <type_traits>
28 #include <variant>
29 #include <vector>
30 
31 #include "napi/native_api.h"
32 #include "napi/native_common.h"
33 #include "napi/native_node_api.h"
34 
35 namespace OHOS {
36 namespace AppDataMgrJsKit {
37 namespace JSUtils {
38 #define DECLARE_JS_PROPERTY(env, key, value) \
39     napi_property_descriptor(DECLARE_NAPI_DEFAULT_PROPERTY((key), Convert2JSValue((env), (value))))
40 
41 #define ASSERT(condition, message, retVal)                       \
42     do {                                                         \
43         if (!(condition)) {                                      \
44             LOG_ERROR("test (" #condition ") failed: " message); \
45             return retVal;                                       \
46         }                                                        \
47     } while (0)
48 static constexpr int OK = 0;
49 static constexpr int ERR = -1;
50 static constexpr uint32_t ASYNC_RST_SIZE = 2;
51 static constexpr uint32_t DEFAULT_VALUE_LENGTH = 1024;
52 static constexpr uint32_t MAX_VALUE_LENGTH = 1024 * 1024 * 8; // the max length of all kand of out string value
53 static constexpr uint32_t SYNC_RESULT_ELEMENT_NUM = 2;
54 struct JsFeatureSpace {
55     const char *spaceName;
56     const char *nameBase64;
57     bool isComponent;
58 };
59 
60 void SetHapVersion(int32_t hapversion);
61 int32_t GetHapVersion();
62 
63 int32_t Convert2Value(napi_env env, napi_value jsValue, napi_value &output);
64 int32_t Convert2Value(napi_env env, napi_value jsValue, bool &output);
65 int32_t Convert2Value(napi_env env, napi_value jsValue, double &output);
66 int32_t Convert2Value(napi_env env, napi_value jsValue, int64_t &output);
67 int32_t Convert2Value(napi_env env, napi_value jsValue, std::string &output);
68 int32_t Convert2Value(napi_env env, napi_value jsValue, std::vector<uint8_t> &output);
69 int32_t Convert2Value(napi_env env, napi_value jsValue, std::vector<float> &output);
70 int32_t Convert2Value(napi_env env, napi_value jsValue, std::monostate &value);
71 int32_t Convert2Value(napi_env env, napi_value jsValue, std::map<std::string, int32_t> &output);
72 int32_t Convert2Value(napi_env env, napi_value jsValue, std::map<std::string, bool> &output);
73 
74 bool IsNull(napi_env env, napi_value value);
75 
76 bool Equal(napi_env env, napi_ref ref, napi_value value);
77 
78 template<typename T>
79 int32_t Convert2Value(napi_env env, napi_value jsValue, T &output);
80 
81 template<typename T>
82 int32_t Convert2ValueExt(napi_env env, napi_value jsValue, T &output);
83 
84 int32_t Convert2ValueExt(napi_env env, napi_value jsValue, uint32_t &output);
85 int32_t Convert2ValueExt(napi_env env, napi_value jsValue, int32_t &output);
86 int32_t Convert2ValueExt(napi_env env, napi_value jsValue, int64_t &output);
87 
88 template<typename T>
89 int32_t Convert2Value(napi_env env, napi_value jsValue, std::vector<T> &value);
90 
91 template<typename T>
92 int32_t Convert2Value(napi_env env, napi_value jsValue, std::map<std::string, T> &value);
93 
94 template<typename... Types>
95 int32_t Convert2Value(napi_env env, napi_value jsValue, std::variant<Types...> &value);
96 
97 using Descriptor = std::function<std::vector<napi_property_descriptor>()>;
98 const std::optional<JsFeatureSpace> GetJsFeatureSpace(const std::string &name);
99 /* napi_define_class  wrapper */
100 napi_value DefineClass(napi_env env, const std::string &spaceName, const std::string &className,
101     const Descriptor &descriptor, napi_callback ctor);
102 napi_value GetClass(napi_env env, const std::string &spaceName, const std::string &className);
103 std::string Convert2String(napi_env env, napi_value jsStr);
104 
105 int32_t Convert2JSValue(napi_env env, std::string value, napi_value &output);
106 int32_t Convert2JSValue(napi_env env, bool value, napi_value &output);
107 int32_t Convert2JSValue(napi_env env, double value, napi_value &output);
108 
109 napi_value Convert2JSValue(napi_env env, const std::string &value);
110 napi_value Convert2JSValue(napi_env env, const std::vector<uint8_t> &value);
111 napi_value Convert2JSValue(napi_env env, const std::vector<float> &value);
112 napi_value Convert2JSValue(napi_env env, int32_t value);
113 napi_value Convert2JSValue(napi_env env, uint32_t value);
114 napi_value Convert2JSValue(napi_env env, int64_t value);
115 napi_value Convert2JSValue(napi_env env, double value);
116 napi_value Convert2JSValue(napi_env env, bool value);
117 napi_value Convert2JSValue(napi_env env, const std::map<std::string, int> &value);
118 napi_value Convert2JSValue(napi_env env, const std::monostate &value);
119 
120 template<typename T>
121 napi_value Convert2JSValue(napi_env env, const T &value);
122 
123 template<typename T>
124 napi_value Convert2JSValue(napi_env env, const std::vector<T> &value);
125 
126 template<typename K, typename V>
127 napi_value Convert2JSValue(napi_env env, const std::map<K, V> &value);
128 
129 template<typename T>
130 napi_value Convert2JSValue(napi_env env, const std::tuple<int32_t, std::string, T> &value);
131 
132 template<typename... Types>
133 napi_value Convert2JSValue(napi_env env, const std::variant<Types...> &value);
134 
135 template<typename T>
136 std::string ToString(const T &key);
137 
138 template<typename K>
139 std::enable_if_t<!std::is_same_v<K, std::string>, std::string> ConvertMapKey(const K &key)
140 {
141     return ToString(key);
142 }
143 
144 template<typename K>
ConvertMapKey(const K & key)145 std::enable_if_t<std::is_same_v<K, std::string>, const std::string &> ConvertMapKey(const K &key)
146 {
147     return key;
148 }
149 
150 template<typename T>
GetCPPValue(napi_env env,napi_value jsValue,T & value)151 int32_t GetCPPValue(napi_env env, napi_value jsValue, T &value)
152 {
153     return napi_invalid_arg;
154 }
155 
156 template<typename T, typename First, typename... Types>
GetCPPValue(napi_env env,napi_value jsValue,T & value)157 int32_t GetCPPValue(napi_env env, napi_value jsValue, T &value)
158 {
159     First cValue;
160     auto ret = Convert2Value(env, jsValue, cValue);
161     if (ret == napi_ok) {
162         value = cValue;
163         return ret;
164     }
165     return GetCPPValue<T, Types...>(env, jsValue, value);
166 }
167 
168 template<typename T>
GetJSValue(napi_env env,const T & value)169 napi_value GetJSValue(napi_env env, const T &value)
170 {
171     return nullptr;
172 }
173 
174 template<typename T, typename First, typename... Types>
GetJSValue(napi_env env,const T & value)175 napi_value GetJSValue(napi_env env, const T &value)
176 {
177     auto *val = std::get_if<First>(&value);
178     if (val != nullptr) {
179         return Convert2JSValue(env, *val);
180     }
181     return GetJSValue<T, Types...>(env, value);
182 }
183 
184 std::pair<napi_status, napi_value> GetInnerValue(napi_env env, napi_value in, const std::string &prop, bool optional);
185 
186 template<typename T>
187 inline std::enable_if_t<std::is_same_v<T, int32_t> || std::is_same_v<T, uint32_t>, int32_t> GetNamedProperty(
188     napi_env env, napi_value in, const std::string &prop, T &value, bool optional = false)
189 {
190     auto [status, jsValue] = GetInnerValue(env, in, prop, optional);
191     if (jsValue == nullptr) {
192         return status;
193     }
194     return Convert2ValueExt(env, jsValue, value);
195 };
196 
197 template<typename T>
198 inline std::enable_if_t<!std::is_same_v<T, int32_t> && !std::is_same_v<T, uint32_t>, int32_t> GetNamedProperty(
199     napi_env env, napi_value in, const std::string &prop, T &value, bool optional = false)
200 {
201     auto [status, jsValue] = GetInnerValue(env, in, prop, optional);
202     if (jsValue == nullptr) {
203         return status;
204     }
205     return Convert2Value(env, jsValue, value);
206 };
207 
208 template<typename T>
SetNamedProperty(napi_env env,napi_value in,const std::string & prop,T value)209 inline int32_t SetNamedProperty(napi_env env, napi_value in, const std::string &prop, T value)
210 {
211     return napi_set_named_property(env, in, prop.c_str(), Convert2JSValue(env, value));
212 };
213 
214 napi_value ToJsObject(napi_env env, napi_value sendableValue);
215 napi_value ToJsArray(napi_env env, napi_value sendableValue);
216 napi_value ToJsTypedArray(napi_env env, napi_value sendableValue);
217 napi_value Convert2JSValue(napi_env env, napi_value sendableValue);
218 } // namespace JSUtils
219 
220 template<typename T>
Convert2Value(napi_env env,napi_value jsValue,std::vector<T> & value)221 int32_t JSUtils::Convert2Value(napi_env env, napi_value jsValue, std::vector<T> &value)
222 {
223     bool isArray = false;
224     napi_is_array(env, jsValue, &isArray);
225     if (!isArray) {
226         return napi_invalid_arg;
227     }
228 
229     uint32_t arrLen = 0;
230     napi_get_array_length(env, jsValue, &arrLen);
231     if (arrLen == 0) {
232         return napi_ok;
233     }
234 
235     for (size_t i = 0; i < arrLen; ++i) {
236         napi_value element;
237         napi_get_element(env, jsValue, i, &element);
238         T item;
239         auto status = Convert2Value(env, element, item);
240         if (status != napi_ok) {
241             return napi_invalid_arg;
242         }
243         value.push_back(std::move(item));
244     }
245     return napi_ok;
246 }
247 
248 template<typename T>
Convert2Value(napi_env env,napi_value jsValue,std::map<std::string,T> & value)249 int32_t JSUtils::Convert2Value(napi_env env, napi_value jsValue, std::map<std::string, T> &value)
250 {
251     napi_value jsMapList = nullptr;
252     uint32_t jsCount = 0;
253     napi_status status = napi_get_property_names(env, jsValue, &jsMapList);
254     if (status != napi_ok) {
255         return napi_invalid_arg;
256     }
257     status = napi_get_array_length(env, jsMapList, &jsCount);
258     if (status != napi_ok || jsCount <= 0) {
259         return napi_invalid_arg;
260     }
261     napi_value jsKey = nullptr;
262     napi_value jsVal = nullptr;
263     for (uint32_t index = 0; index < jsCount; index++) {
264         status = napi_get_element(env, jsMapList, index, &jsKey);
265         if (status != napi_ok) {
266             return napi_invalid_arg;
267         }
268         std::string key;
269         int ret = Convert2Value(env, jsKey, key);
270         if (status != napi_ok) {
271             return napi_invalid_arg;
272         }
273         status = napi_get_property(env, jsValue, jsKey, &jsVal);
274         if (status != napi_ok || jsVal == nullptr) {
275             return napi_invalid_arg;
276         }
277         T val;
278         ret = Convert2Value(env, jsVal, val);
279         if (status != napi_ok) {
280             return napi_invalid_arg;
281         }
282         value.insert(std::pair<std::string, T>(key, val));
283     }
284     return napi_ok;
285 }
286 
287 template<typename K, typename V>
Convert2JSValue(napi_env env,const std::map<K,V> & value)288 napi_value JSUtils::Convert2JSValue(napi_env env, const std::map<K, V> &value)
289 {
290     napi_value jsValue;
291     napi_status status = napi_create_object(env, &jsValue);
292     if (status != napi_ok) {
293         return nullptr;
294     }
295 
296     for (const auto &[key, val] : value) {
297         const std::string &name = ConvertMapKey(key);
298         status = napi_set_named_property(env, jsValue, name.c_str(), Convert2JSValue(env, val));
299         if (status != napi_ok) {
300             return nullptr;
301         }
302     }
303     return jsValue;
304 }
305 
306 template<typename T>
Convert2JSValue(napi_env env,const std::tuple<int32_t,std::string,T> & value)307 napi_value JSUtils::Convert2JSValue(napi_env env, const std::tuple<int32_t, std::string, T> &value)
308 {
309     napi_value jsValue;
310     napi_status status = napi_create_object(env, &jsValue);
311     if (status != napi_ok) {
312         return nullptr;
313     }
314     napi_value code = Convert2JSValue(env, std::get<0>(value));
315     napi_value description = Convert2JSValue(env, std::get<1>(value));
316     napi_value val = Convert2JSValue(env, std::get<2>(value));
317     if (description == nullptr || val == nullptr) {
318         return nullptr;
319     }
320     napi_set_named_property(env, jsValue, "code", code);
321     napi_set_named_property(env, jsValue, "description", description);
322     napi_set_named_property(env, jsValue, "value", val);
323     return jsValue;
324 }
325 
326 template<typename... Types>
Convert2Value(napi_env env,napi_value jsValue,std::variant<Types...> & value)327 int32_t JSUtils::Convert2Value(napi_env env, napi_value jsValue, std::variant<Types...> &value)
328 {
329     napi_valuetype type = napi_undefined;
330     napi_status status = napi_typeof(env, jsValue, &type);
331     if (status != napi_ok) {
332         return napi_invalid_arg;
333     }
334     if (type == napi_undefined) {
335         return napi_generic_failure;
336     }
337 
338     return GetCPPValue<decltype(value), Types...>(env, jsValue, value);
339 }
340 
341 template<typename T>
Convert2JSValue(napi_env env,const std::vector<T> & value)342 napi_value JSUtils::Convert2JSValue(napi_env env, const std::vector<T> &value)
343 {
344     napi_value jsValue;
345     napi_status status = napi_create_array_with_length(env, value.size(), &jsValue);
346     if (status != napi_ok) {
347         return nullptr;
348     }
349 
350     for (size_t i = 0; i < value.size(); ++i) {
351         napi_set_element(env, jsValue, i, Convert2JSValue(env, value[i]));
352     }
353     return jsValue;
354 }
355 
356 template<typename... Types>
Convert2JSValue(napi_env env,const std::variant<Types...> & value)357 napi_value JSUtils::Convert2JSValue(napi_env env, const std::variant<Types...> &value)
358 {
359     return GetJSValue<decltype(value), Types...>(env, value);
360 }
361 } // namespace AppDataMgrJsKit
362 } // namespace OHOS
363 #endif // DISTRIBUTEDDATAMGR_APPDATAMGR_JSUTILS_H