1 /*
2 * Copyright (c) 2023 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 "NapiDataUtils"
16 #include "napi_data_utils.h"
17
18 namespace OHOS {
19 namespace UDMF {
20 constexpr int32_t STR_MAX_LENGTH = 4096;
21 constexpr size_t STR_TAIL_LENGTH = 1;
22
23 static const std::map<napi_valuetype, ValueType> objectValueTypeMap = {
24 {napi_valuetype::napi_number, double()},
25 {napi_valuetype::napi_string, std::string()},
26 {napi_valuetype::napi_boolean, bool()},
27 {napi_valuetype::napi_undefined, std::monostate()},
28 {napi_valuetype::napi_null, nullptr}
29 };
30
31 static const std::set<std::string> udsAttributeKeySet = {"details", "thumbData", "appIcon", "arrayBuffer"};
32 /* napi_value <-> bool */
GetValue(napi_env env,napi_value in,bool & out)33 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, bool &out)
34 {
35 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- bool");
36 return napi_get_value_bool(env, in, &out);
37 }
38
SetValue(napi_env env,const bool & in,napi_value & out)39 napi_status NapiDataUtils::SetValue(napi_env env, const bool &in, napi_value &out)
40 {
41 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> bool");
42 return napi_get_boolean(env, in, &out);
43 }
44
45 /* napi_value <-> int32_t */
GetValue(napi_env env,napi_value in,int32_t & out)46 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, int32_t &out)
47 {
48 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> int32_t");
49 return napi_get_value_int32(env, in, &out);
50 }
51
SetValue(napi_env env,const int32_t & in,napi_value & out)52 napi_status NapiDataUtils::SetValue(napi_env env, const int32_t &in, napi_value &out)
53 {
54 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- int32_t");
55 return napi_create_int32(env, in, &out);
56 }
57
58 /* napi_value <-> uint32_t */
GetValue(napi_env env,napi_value in,uint32_t & out)59 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, uint32_t &out)
60 {
61 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> int32_t");
62 return napi_get_value_uint32(env, in, &out);
63 }
64
SetValue(napi_env env,const uint32_t & in,napi_value & out)65 napi_status NapiDataUtils::SetValue(napi_env env, const uint32_t &in, napi_value &out)
66 {
67 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- int32_t");
68 return napi_create_uint32(env, in, &out);
69 }
70
71 /* napi_value <-> int64_t */
GetValue(napi_env env,napi_value in,int64_t & out)72 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, int64_t &out)
73 {
74 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> int64_t");
75 return napi_get_value_int64(env, in, &out);
76 }
77
SetValue(napi_env env,const int64_t & in,napi_value & out)78 napi_status NapiDataUtils::SetValue(napi_env env, const int64_t &in, napi_value &out)
79 {
80 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- int64_t");
81 return napi_create_int64(env, in, &out);
82 }
83
84 /* napi_value <-> float */
GetValue(napi_env env,napi_value in,float & out)85 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, float &out)
86 {
87 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> float");
88 double tmp;
89 napi_status status = napi_get_value_double(env, in, &tmp);
90 out = tmp;
91 return status;
92 }
93
SetValue(napi_env env,const float & in,napi_value & out)94 napi_status NapiDataUtils::SetValue(napi_env env, const float &in, napi_value &out)
95 {
96 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- float");
97 double tmp = in;
98 return napi_create_double(env, tmp, &out);
99 }
100
101 /* napi_value <-> double */
GetValue(napi_env env,napi_value in,double & out)102 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, double &out)
103 {
104 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> double");
105 return napi_get_value_double(env, in, &out);
106 }
107
SetValue(napi_env env,const double & in,napi_value & out)108 napi_status NapiDataUtils::SetValue(napi_env env, const double &in, napi_value &out)
109 {
110 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- double");
111 return napi_create_double(env, in, &out);
112 }
113
114 /* napi_value <-> std::string */
GetValue(napi_env env,napi_value in,std::string & out)115 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, std::string &out)
116 {
117 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- string");
118 napi_valuetype type = napi_undefined;
119 napi_status status = napi_typeof(env, in, &type);
120 LOG_ERROR_RETURN((status == napi_ok) && (type == napi_string), "invalid type", napi_invalid_arg);
121
122 size_t maxLen = STR_MAX_LENGTH;
123 status = napi_get_value_string_utf8(env, in, NULL, 0, &maxLen);
124 if (maxLen == 0) {
125 return status;
126 }
127 char *buf = new (std::nothrow) char[maxLen + STR_TAIL_LENGTH];
128 if (buf != nullptr) {
129 size_t len = 0;
130 status = napi_get_value_string_utf8(env, in, buf, maxLen + STR_TAIL_LENGTH, &len);
131 if (status == napi_ok) {
132 buf[len] = 0;
133 out = std::string(buf);
134 }
135 delete[] buf;
136 } else {
137 status = napi_generic_failure;
138 }
139 return status;
140 }
141
SetValue(napi_env env,const std::string & in,napi_value & out)142 napi_status NapiDataUtils::SetValue(napi_env env, const std::string &in, napi_value &out)
143 {
144 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- std::string %{public}d", (int)in.length());
145 return napi_create_string_utf8(env, in.c_str(), in.size(), &out);
146 }
147
148 /* napi_value <-> std::vector<std::string> */
GetValue(napi_env env,napi_value in,std::vector<std::string> & out)149 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, std::vector<std::string> &out)
150 {
151 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> std::vector<std::string>");
152 bool isArray = false;
153 napi_is_array(env, in, &isArray);
154 LOG_ERROR_RETURN(isArray, "not an array", napi_invalid_arg);
155
156 uint32_t length = 0;
157 napi_status status = napi_get_array_length(env, in, &length);
158 LOG_ERROR_RETURN((status == napi_ok) && (length > 0), "get_array failed!", napi_invalid_arg);
159 for (uint32_t i = 0; i < length; ++i) {
160 napi_value item = nullptr;
161 status = napi_get_element(env, in, i, &item);
162 LOG_ERROR_RETURN((item != nullptr) && (status == napi_ok), "no element", napi_invalid_arg);
163 std::string value;
164 status = GetValue(env, item, value);
165 LOG_ERROR_RETURN(status == napi_ok, "not a string", napi_invalid_arg);
166 out.push_back(value);
167 }
168 return status;
169 }
170
SetValue(napi_env env,const std::vector<std::string> & in,napi_value & out)171 napi_status NapiDataUtils::SetValue(napi_env env, const std::vector<std::string> &in, napi_value &out)
172 {
173 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- std::vector<std::string>");
174 napi_status status = napi_create_array_with_length(env, in.size(), &out);
175 LOG_ERROR_RETURN(status == napi_ok, "create array failed!", status);
176 int index = 0;
177 for (auto &item : in) {
178 napi_value element = nullptr;
179 SetValue(env, item, element);
180 status = napi_set_element(env, out, index++, element);
181 LOG_ERROR_RETURN((status == napi_ok), "napi_set_element failed!", status);
182 }
183 return status;
184 }
185
186 /* napi_value <-> std::vector<uint8_t> */
GetValue(napi_env env,napi_value in,std::vector<uint8_t> & out)187 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, std::vector<uint8_t> &out)
188 {
189 out.clear();
190 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> std::vector<uint8_t> ");
191
192 bool isTypedArray = false;
193 auto status = napi_is_typedarray(env, in, &isTypedArray);
194 if (status != napi_ok || !isTypedArray) {
195 return napi_invalid_arg;
196 }
197
198 napi_typedarray_type type = napi_biguint64_array;
199 size_t length = 0;
200 napi_value buffer = nullptr;
201 size_t offset = 0;
202 void *data = nullptr;
203 status = napi_get_typedarray_info(env, in, &type, &length, &data, &buffer, &offset);
204 LOG_DEBUG(UDMF_KITS_NAPI, "array type=%{public}d length=%{public}d offset=%{public}d status=%{public}d",
205 (int)type, (int)length, (int)offset, status);
206 LOG_ERROR_RETURN(status == napi_ok, "napi_get_typedarray_info failed!", napi_invalid_arg);
207 LOG_ERROR_RETURN(type == napi_uint8_array, "is not Uint8Array!", napi_invalid_arg);
208 if (length > 0) {
209 out.assign(static_cast<uint8_t *>(data), static_cast<uint8_t *>(data) + length);
210 }
211 return status;
212 }
213
SetValue(napi_env env,const std::vector<uint8_t> & in,napi_value & out)214 napi_status NapiDataUtils::SetValue(napi_env env, const std::vector<uint8_t> &in, napi_value &out)
215 {
216 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- std::vector<uint8_t> ");
217 LOG_ERROR_RETURN(in.size() > 0, "invalid std::vector<uint8_t>", napi_invalid_arg);
218 void *data = nullptr;
219 napi_value buffer = nullptr;
220 napi_status status = napi_create_arraybuffer(env, in.size(), &data, &buffer);
221 LOG_ERROR_RETURN((status == napi_ok), "create array buffer failed!", status);
222
223 if (memcpy_s(data, in.size(), in.data(), in.size()) != EOK) {
224 LOG_ERROR(UDMF_KITS_NAPI, "memcpy_s not EOK");
225 return napi_invalid_arg;
226 }
227 status = napi_create_typedarray(env, napi_uint8_array, in.size(), buffer, 0, &out);
228 LOG_ERROR_RETURN((status == napi_ok), "napi_value <- std::vector<uint8_t> invalid value", status);
229 return status;
230 }
231
232 /* napi_value <-> std::map<std::string, int32_t> */
GetValue(napi_env env,napi_value in,std::map<std::string,int32_t> & out)233 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, std::map<std::string, int32_t> &out)
234 {
235 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> std::map<std::string, int32_t> ");
236 (void)(env);
237 (void)(in);
238 (void)(out);
239 LOG_ERROR_RETURN(false, "std::map<std::string, uint32_t> from napi_value, unsupported!", napi_invalid_arg);
240 return napi_invalid_arg;
241 }
242
SetValue(napi_env env,const std::map<std::string,int32_t> & in,napi_value & out)243 napi_status NapiDataUtils::SetValue(napi_env env, const std::map<std::string, int32_t> &in, napi_value &out)
244 {
245 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- std::map<std::string, int32_t> ");
246 napi_status status = napi_create_array_with_length(env, in.size(), &out);
247 LOG_ERROR_RETURN((status == napi_ok), "invalid object", status);
248 int index = 0;
249 for (const auto &[key, value] : in) {
250 napi_value element = nullptr;
251 napi_create_array_with_length(env, TUPLE_SIZE, &element);
252 napi_value jsKey = nullptr;
253 napi_create_string_utf8(env, key.c_str(), key.size(), &jsKey);
254 napi_set_element(env, element, TUPLE_KEY, jsKey);
255 napi_value jsValue = nullptr;
256 napi_create_int32(env, static_cast<int32_t>(value), &jsValue);
257 napi_set_element(env, element, TUPLE_VALUE, jsValue);
258 napi_set_element(env, out, index++, element);
259 }
260 return status;
261 }
262
263 /* napi_value <-> std::map<std::string, int64_t> */
GetValue(napi_env env,napi_value in,std::map<std::string,int64_t> & out)264 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, std::map<std::string, int64_t> &out)
265 {
266 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> std::map<std::string, int64_t> ");
267 (void)(env);
268 (void)(in);
269 (void)(out);
270 LOG_ERROR_RETURN(false, "std::map<std::string, int64_t> from napi_value, unsupported!", napi_invalid_arg);
271 return napi_invalid_arg;
272 }
273
SetValue(napi_env env,const std::map<std::string,int64_t> & in,napi_value & out)274 napi_status NapiDataUtils::SetValue(napi_env env, const std::map<std::string, int64_t> &in, napi_value &out)
275 {
276 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- std::map<std::string, int64_t> ");
277 napi_status status = napi_create_array_with_length(env, in.size(), &out);
278 LOG_ERROR_RETURN((status == napi_ok), "invalid object", status);
279 int index = 0;
280 for (const auto &[key, value] : in) {
281 napi_value element = nullptr;
282 napi_create_array_with_length(env, TUPLE_SIZE, &element);
283 napi_value jsKey = nullptr;
284 napi_create_string_utf8(env, key.c_str(), key.size(), &jsKey);
285 napi_set_element(env, element, TUPLE_KEY, jsKey);
286 napi_value jsValue = nullptr;
287 napi_create_int64(env, static_cast<int64_t>(value), &jsValue);
288 napi_set_element(env, element, TUPLE_VALUE, jsValue);
289 napi_set_element(env, out, index++, element);
290 }
291 return status;
292 }
293
GetValue(napi_env env,napi_value in,std::set<std::string> & out)294 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, std::set<std::string> &out)
295 {
296 napi_value global;
297 napi_value iterator;
298 napi_value values_fn;
299 napi_get_global(env, &global);
300 napi_get_named_property(env, in, "values", &values_fn);
301 napi_call_function(env, in, values_fn, 0, nullptr, &iterator);
302
303 napi_value next_fn;
304 napi_value result_obj;
305 napi_value done_val;
306 napi_value value_val;
307 bool done = false;
308
309 while (!done) {
310 napi_get_named_property(env, iterator, "next", &next_fn);
311 napi_call_function(env, iterator, next_fn, 0, nullptr, &result_obj);
312
313 napi_get_named_property(env, result_obj, "done", &done_val);
314 napi_get_value_bool(env, done_val, &done);
315 if (done) break;
316
317 napi_get_named_property(env, result_obj, "value", &value_val);
318
319 size_t str_len;
320 napi_get_value_string_utf8(env, value_val, nullptr, 0, &str_len);
321 std::string str(str_len, '\0');
322 napi_get_value_string_utf8(env, value_val, &str[0], str_len + 1, nullptr);
323
324 out.insert(str);
325 }
326 return napi_ok;
327 }
328
SetValue(napi_env env,const std::set<std::string> & in,napi_value & out)329 napi_status NapiDataUtils::SetValue(napi_env env, const std::set<std::string> &in, napi_value &out)
330 {
331 std::vector<std::string> vec(in.begin(), in.end());
332 napi_value jsArray;
333 NapiDataUtils::SetValue(env, vec, jsArray);
334
335 napi_value global;
336 napi_get_global(env, &global);
337
338 napi_value setConstructor;
339 napi_get_named_property(env, global, "Set", &setConstructor);
340
341 napi_value argv[1] = { jsArray };
342 napi_new_instance(env, setConstructor, 1, argv, &out);
343 return napi_ok;
344 }
345
346 /* napi_value <-> UDVariant */
GetValue(napi_env env,napi_value in,UDVariant & out)347 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, UDVariant &out)
348 {
349 napi_valuetype type = napi_undefined;
350 napi_status status = napi_typeof(env, in, &type);
351 LOG_ERROR_RETURN((status == napi_ok), "invalid type", status);
352 switch (type) {
353 case napi_boolean: {
354 bool vBool = false;
355 status = GetValue(env, in, vBool);
356 out = vBool;
357 break;
358 }
359 case napi_number: {
360 double vNum = 0.0f;
361 status = GetValue(env, in, vNum);
362 out = vNum;
363 break;
364 }
365 case napi_string: {
366 std::string vString;
367 status = GetValue(env, in, vString);
368 out = vString;
369 break;
370 }
371 case napi_object: {
372 std::vector<uint8_t> vct;
373 status = GetValue(env, in, vct);
374 out = vct;
375 break;
376 }
377 default:
378 LOG_ERROR(UDMF_KITS_NAPI,
379 "napi_value <- UDVariant not [Uint8Array | string | boolean | number] type=%{public}d", type);
380 status = napi_invalid_arg;
381 break;
382 }
383 return status;
384 }
385
SetValue(napi_env env,const UDVariant & in,napi_value & out)386 napi_status NapiDataUtils::SetValue(napi_env env, const UDVariant &in, napi_value &out)
387 {
388 auto strValue = std::get_if<std::string>(&in);
389 if (strValue != nullptr) {
390 return SetValue(env, *strValue, out);
391 }
392 auto intValue = std::get_if<int32_t>(&in);
393 if (intValue != nullptr) {
394 return SetValue(env, *intValue, out);
395 }
396 auto pUint8 = std::get_if<std::vector<uint8_t>>(&in);
397 if (pUint8 != nullptr) {
398 return SetValue(env, *pUint8, out);
399 }
400 auto boolValue = std::get_if<bool>(&in);
401 if (boolValue != nullptr) {
402 return SetValue(env, *boolValue, out);
403 }
404 auto dblValue = std::get_if<double>(&in);
405 if (dblValue != nullptr) {
406 return SetValue(env, *dblValue, out);
407 }
408
409 LOG_ERROR(UDMF_KITS_NAPI, "napi_value <- UDVariant INVALID value type");
410 return napi_invalid_arg;
411 }
412
413 /* napi_value <-> UDDetails */
GetValue(napi_env env,napi_value in,UDDetails & out)414 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, UDDetails &out)
415 {
416 if (!IsTypeForNapiValue(env, in, napi_object)) {
417 return napi_invalid_arg;
418 }
419 napi_value jsProNameList = nullptr;
420 uint32_t jsProCount = 0;
421
422 NAPI_CALL_BASE(env, napi_get_property_names(env, in, &jsProNameList), napi_invalid_arg);
423 NAPI_CALL_BASE(env, napi_get_array_length(env, jsProNameList, &jsProCount), napi_invalid_arg);
424
425 napi_value jsProName = nullptr;
426 napi_value jsProValue = nullptr;
427 for (uint32_t index = 0; index < jsProCount; index++) {
428 NAPI_CALL_BASE(env, napi_get_element(env, jsProNameList, index, &jsProName), napi_invalid_arg);
429 if (!IsTypeForNapiValue(env, jsProName, napi_string)) {
430 return napi_invalid_arg;
431 }
432 std::string strProName;
433 GetValue(env, jsProName, strProName);
434
435 NAPI_CALL_BASE(env, napi_get_named_property(env, in, strProName.c_str(), &jsProValue), napi_invalid_arg);
436 UDVariant natValue;
437 GetValue(env, jsProValue, natValue);
438 out[strProName] = natValue;
439 }
440 return napi_ok;
441 }
442
SetValue(napi_env env,const UDDetails & in,napi_value & out)443 napi_status NapiDataUtils::SetValue(napi_env env, const UDDetails &in, napi_value &out)
444 {
445 NAPI_CALL_BASE(env, napi_create_object(env, &out), napi_invalid_arg);
446 for (std::pair<std::string, UDVariant> prop : in) {
447 napi_value jsProValue = nullptr;
448 SetValue(env, prop.second, jsProValue);
449 NAPI_CALL_BASE(env, napi_set_named_property(env, out, prop.first.c_str(), jsProValue), napi_invalid_arg);
450 }
451 return napi_ok;
452 }
453
GetValue(napi_env env,napi_value in,std::shared_ptr<TypeDescriptor> & descriptor)454 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, std::shared_ptr<TypeDescriptor> &descriptor)
455 {
456 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> std::GetValue TypeDescriptor");
457 napi_valuetype type = napi_undefined;
458 napi_status status = napi_typeof(env, in, &type);
459 LOG_ERROR_RETURN((status == napi_ok) && (type == napi_object), "invalid type", napi_invalid_arg);
460 TypeDescriptorNapi *descriptorNapi = nullptr;
461 auto unwrap = napi_unwrap(env, in, reinterpret_cast<void **>(&descriptorNapi));
462 LOG_ERROR_RETURN((descriptorNapi != nullptr || unwrap == napi_ok), "invalid type", napi_invalid_arg);
463 descriptor = descriptorNapi->value_;
464 if (descriptor == nullptr) {
465 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> GetValue TypeDescriptor failed ");
466 }
467 return napi_ok;
468 }
469
GetValue(napi_env env,napi_value in,std::shared_ptr<OHOS::Media::PixelMap> & pixelMap)470 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, std::shared_ptr<OHOS::Media::PixelMap> &pixelMap)
471 {
472 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> std::shared_ptr<OHOS::Media::PixelMap>");
473 pixelMap = OHOS::Media::PixelMapNapi::GetPixelMap(env, in);
474 return napi_ok;
475 }
476
SetValue(napi_env env,const std::shared_ptr<OHOS::Media::PixelMap> & in,napi_value & out)477 napi_status NapiDataUtils::SetValue(napi_env env, const std::shared_ptr<OHOS::Media::PixelMap> &in, napi_value &out)
478 {
479 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- std::shared_ptr<OHOS::Media::PixelMap>");
480 out = OHOS::Media::PixelMapNapi::CreatePixelMap(env, in);
481 return napi_ok;
482 }
483
GetValue(napi_env env,napi_value in,std::shared_ptr<OHOS::AAFwk::Want> & wantPtr)484 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, std::shared_ptr<OHOS::AAFwk::Want> &wantPtr)
485 {
486 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> std::shared_ptr<OHOS::AAFwk::Want>");
487 OHOS::AAFwk::Want want;
488 AppExecFwk::UnwrapWant(env, in, want);
489 wantPtr = std::make_shared<OHOS::AAFwk::Want>(want);
490 return napi_ok;
491 }
492
SetValue(napi_env env,const std::shared_ptr<OHOS::AAFwk::Want> & in,napi_value & out)493 napi_status NapiDataUtils::SetValue(napi_env env, const std::shared_ptr<OHOS::AAFwk::Want> &in, napi_value &out)
494 {
495 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- std::shared_ptr<OHOS::AAFwk::Want>");
496 out = OHOS::AppExecFwk::WrapWant(env, *in);
497 return napi_ok;
498 }
499
GetValue(napi_env env,napi_value in,std::shared_ptr<Object> & object)500 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, std::shared_ptr<Object> &object)
501 {
502 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> std::GetValue Object");
503 napi_value attributeNames = nullptr;
504 NAPI_CALL_BASE(env, napi_get_property_names(env, in, &attributeNames), napi_invalid_arg);
505 uint32_t attributesNum = 0;
506 NAPI_CALL_BASE(env, napi_get_array_length(env, attributeNames, &attributesNum), napi_invalid_arg);
507 for (uint32_t i = 0; i < attributesNum; i++) {
508 napi_value attributeNameNapi = nullptr;
509 NAPI_CALL_BASE(env, napi_get_element(env, attributeNames, i, &attributeNameNapi), napi_invalid_arg);
510 size_t len = 0;
511 char str[STR_MAX_SIZE] = { 0 };
512 NAPI_CALL_BASE(env, napi_get_value_string_utf8(
513 env, attributeNameNapi, str, STR_MAX_SIZE, &len), napi_invalid_arg);
514 std::string attributeName = str;
515 napi_value attributeValueNapi = nullptr;
516 NAPI_CALL_BASE(env, napi_get_named_property(env, in, str, &attributeValueNapi), napi_invalid_arg);
517
518 bool isArrayBuffer = false;
519 NAPI_CALL_BASE(env, napi_is_arraybuffer(env, attributeValueNapi, &isArrayBuffer), napi_invalid_arg);
520 if (isArrayBuffer) {
521 void *data = nullptr;
522 size_t dataLen = 0;
523 NAPI_CALL_BASE(env, napi_get_arraybuffer_info(env, attributeValueNapi, &data, &dataLen), napi_invalid_arg);
524 object->value_[attributeName] = std::vector<uint8_t>(
525 reinterpret_cast<uint8_t *>(data), reinterpret_cast<uint8_t *>(data) + dataLen);
526 continue;
527 }
528 napi_valuetype valueType = napi_undefined;
529 NAPI_CALL_BASE(env, napi_typeof(env, attributeValueNapi, &valueType), napi_invalid_arg);
530 napi_status status = napi_ok;
531 if (valueType == napi_valuetype::napi_object) {
532 status = ProcessNapiObject(env, in, attributeName, attributeValueNapi, object);
533 if (status != napi_ok) {
534 return status;
535 }
536 } else {
537 auto it = objectValueTypeMap.find(valueType);
538 if (it != objectValueTypeMap.end()) {
539 object->value_[attributeName] = it->second;
540 } else {
541 return napi_invalid_arg;
542 }
543 }
544 std::visit([&](auto &value) {status = NapiDataUtils::GetValue(env, attributeValueNapi, value);},
545 object->value_[attributeName]);
546 if (status != napi_ok) {
547 return status;
548 }
549 }
550 return napi_ok;
551 }
552
ProcessNapiObject(napi_env env,napi_value in,std::string & attributeName,napi_value attributeValueNapi,std::shared_ptr<Object> object)553 napi_status NapiDataUtils::ProcessNapiObject(napi_env env, napi_value in, std::string &attributeName,
554 napi_value attributeValueNapi, std::shared_ptr<Object> object)
555 {
556 if (attributeName == PIXEL_MAP) {
557 object->value_[attributeName] = std::shared_ptr<OHOS::Media::PixelMap>();
558 return napi_ok;
559 }
560 bool isUint8Array = false;
561 napi_value constructor = nullptr;
562 NAPI_CALL_BASE(env, napi_get_named_property(env, attributeValueNapi, "constructor", &constructor),
563 napi_invalid_arg);
564 napi_value global = nullptr;
565 NAPI_CALL_BASE(env, napi_get_global(env, &global), napi_invalid_arg);
566 napi_value uint8ArrayConstructor = nullptr;
567 NAPI_CALL_BASE(env, napi_get_named_property(env, global, "Uint8Array", &uint8ArrayConstructor), napi_invalid_arg);
568 NAPI_CALL_BASE(env, napi_strict_equals(env, constructor, uint8ArrayConstructor, &isUint8Array), napi_invalid_arg);
569 if (isUint8Array && (udsAttributeKeySet.find(attributeName) != udsAttributeKeySet.end())) {
570 napi_value jsProValue = nullptr;
571 NAPI_CALL_BASE(env, napi_get_named_property(env, in, attributeName.c_str(), &jsProValue), napi_invalid_arg);
572 std::vector<uint8_t> array;
573 auto status = GetValue(env, jsProValue, array);
574 if (status != napi_ok) {
575 LOG_ERROR(UDMF_KITS_NAPI, "Get Uint8Array error: %{public}d", status);
576 return status;
577 }
578 object->value_[attributeName] = array;
579 return napi_ok;
580 }
581 object->value_[attributeName] = std::make_shared<Object>();
582 return napi_ok;
583 }
584
SetValue(napi_env env,const std::shared_ptr<Object> & object,napi_value & out)585 napi_status NapiDataUtils::SetValue(napi_env env, const std::shared_ptr<Object> &object, napi_value &out)
586 {
587 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> std::GetValue Object");
588 napi_create_object(env, &out);
589 for (auto &[key, value] : object->value_) {
590 napi_value valueNapi = nullptr;
591 if (std::holds_alternative<std::vector<uint8_t>>(value) &&
592 (udsAttributeKeySet.find(key) == udsAttributeKeySet.end())) {
593 auto array = std::get<std::vector<uint8_t>>(value);
594 void *data = nullptr;
595 size_t len = array.size();
596 NAPI_CALL_BASE(env, napi_create_arraybuffer(env, len, &data, &valueNapi), napi_generic_failure);
597 if (memcpy_s(data, len, reinterpret_cast<const void *>(array.data()), len) != 0) {
598 LOG_ERROR(UDMF_KITS_NAPI, "memcpy_s failed");
599 return napi_generic_failure;
600 }
601 } else if (std::holds_alternative<std::vector<uint8_t>>(value) &&
602 (udsAttributeKeySet.find(key) != udsAttributeKeySet.end())) {
603 auto array = std::get<std::vector<uint8_t>>(value);
604 void *data = nullptr;
605 napi_value buffer = nullptr;
606 NAPI_CALL_BASE(env, napi_create_arraybuffer(env, array.size(), &data, &buffer), napi_generic_failure);
607 if (!array.empty() && memcpy_s(data, array.size(), array.data(), array.size()) != 0) {
608 LOG_ERROR(UDMF_KITS_NAPI, "memcpy_s failed");
609 return napi_generic_failure;
610 }
611 NAPI_CALL_BASE(env, napi_create_typedarray(env, napi_uint8_array, array.size(), buffer, 0, &valueNapi),
612 napi_generic_failure);
613 } else {
614 std::visit([&](const auto &value) {NapiDataUtils::SetValue(env, value, valueNapi);}, value);
615 }
616 napi_set_named_property(env, out, key.c_str(), valueNapi);
617 }
618 return napi_ok;
619 }
620
GetValue(napi_env env,napi_value in,std::monostate & out)621 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, std::monostate &out)
622 {
623 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> std::monostate");
624 out = std::monostate{};
625 return napi_ok;
626 }
627
SetValue(napi_env env,const std::monostate & in,napi_value & out)628 napi_status NapiDataUtils::SetValue(napi_env env, const std::monostate &in, napi_value &out)
629 {
630 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- std::monostate");
631 return napi_get_undefined(env, &out);
632 }
633
GetValue(napi_env env,napi_value in,nullptr_t & out)634 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, nullptr_t &out)
635 {
636 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> null");
637 out = nullptr;
638 return napi_ok;
639 }
640
SetValue(napi_env env,const nullptr_t & in,napi_value & out)641 napi_status NapiDataUtils::SetValue(napi_env env, const nullptr_t &in, napi_value &out)
642 {
643 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- null");
644 return napi_get_null(env, &out);
645 }
646
SetValue(napi_env env,const ProgressInfo & in,napi_value & out)647 napi_status NapiDataUtils::SetValue(napi_env env, const ProgressInfo &in, napi_value &out)
648 {
649 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- ProgressInfo");
650 napi_create_object(env, &out);
651
652 napi_value jsPercentage = nullptr;
653 SetValue(env, in.progress, jsPercentage);
654 NAPI_CALL_BASE(env, napi_set_named_property(env, out, "progress", jsPercentage), napi_invalid_arg);
655
656 napi_value jsListenerStatus = nullptr;
657 SetValue(env, in.progressStatus, jsListenerStatus);
658 NAPI_CALL_BASE(env, napi_set_named_property(env, out, "status", jsListenerStatus), napi_invalid_arg);
659 return napi_ok;
660 }
661
SetValue(napi_env env,const DataLoadInfo & in,napi_value & out)662 napi_status NapiDataUtils::SetValue(napi_env env, const DataLoadInfo &in, napi_value &out)
663 {
664 LOG_ERROR(UDMF_KITS_NAPI, "napi_value <- DataLoadInfo");
665 napi_create_object(env, &out);
666
667 napi_value jsRecordCount = nullptr;
668 NAPI_CALL_BASE(env, SetValue(env, in.recordCount, jsRecordCount), napi_invalid_arg);
669 NAPI_CALL_BASE(env, napi_set_named_property(env, out, "recordCount", jsRecordCount), napi_invalid_arg);
670
671 napi_value jsTypes = nullptr;
672 NAPI_CALL_BASE(env, SetValue(env, in.types, jsTypes), napi_invalid_arg);
673 NAPI_CALL_BASE(env, napi_set_named_property(env, out, "types", jsTypes), napi_invalid_arg);
674 return napi_ok;
675 }
676
GetValue(napi_env env,napi_value in,DataLoadInfo & out)677 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, DataLoadInfo &out)
678 {
679 LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> DataLoadInfo");
680 napi_value jsTypes = nullptr;
681 NAPI_CALL_BASE(env, GetOptionalNamedProperty(env, in, "types", jsTypes), napi_invalid_arg);
682 if (jsTypes != nullptr) {
683 NAPI_CALL_BASE(env, NapiDataUtils::GetValue(env, jsTypes, out.types), napi_invalid_arg);
684 }
685
686 out.recordCount = 0;
687 napi_value jsRecordCount = nullptr;
688 NAPI_CALL_BASE(env, GetOptionalNamedProperty(env, in, "recordCount", jsRecordCount), napi_invalid_arg);
689 if (jsRecordCount != nullptr) {
690 double count = 0;
691 NAPI_CALL_BASE(env, NapiDataUtils::GetValue(env, jsRecordCount, count), napi_invalid_arg);
692 if (!std::isfinite(count)) {
693 LOG_WARN(UDMF_KITS_NAPI, "recordCount is not a finite number");
694 return napi_ok;
695 }
696 count = std::floor(count);
697 if (count < 0 || count > static_cast<double>(UINT32_MAX)) {
698 LOG_WARN(UDMF_KITS_NAPI, "recordCount out of range: %{public}f", count);
699 return napi_ok;
700 }
701 out.recordCount = static_cast<uint32_t>(count);
702 }
703 return napi_ok;
704 }
705
IsTypeForNapiValue(napi_env env,napi_value param,napi_valuetype expectType)706 bool NapiDataUtils::IsTypeForNapiValue(napi_env env, napi_value param, napi_valuetype expectType)
707 {
708 napi_valuetype valueType = napi_undefined;
709
710 if (param == nullptr) {
711 return false;
712 }
713
714 if (napi_typeof(env, param, &valueType) != napi_ok) {
715 return false;
716 }
717
718 return valueType == expectType;
719 }
720
IsNull(napi_env env,napi_value value)721 bool NapiDataUtils::IsNull(napi_env env, napi_value value)
722 {
723 napi_valuetype type = napi_undefined;
724 napi_status status = napi_typeof(env, value, &type);
725 if (status == napi_ok && (type == napi_undefined || type == napi_null)) {
726 return true;
727 }
728 if (type == napi_string) {
729 size_t len;
730 napi_get_value_string_utf8(env, value, NULL, 0, &len);
731 return len == 0;
732 }
733 return false;
734 }
735
IsUndefinedOrNull(napi_env env,napi_value value)736 bool NapiDataUtils::IsUndefinedOrNull(napi_env env, napi_value value)
737 {
738 napi_valuetype type = napi_undefined;
739 napi_status status = napi_typeof(env, value, &type);
740 if (status == napi_ok && (type == napi_undefined || type == napi_null)) {
741 return true;
742 }
743 return false;
744 }
745
DefineClass(napi_env env,const std::string & name,const napi_property_descriptor * properties,size_t count,napi_callback newcb)746 napi_value NapiDataUtils::DefineClass(napi_env env, const std::string &name,
747 const napi_property_descriptor *properties, size_t count, napi_callback newcb)
748 {
749 // base64("data.udmf") as rootPropName, i.e. global.<root>
750 constexpr const char *rootPropName = "ZGF0YS51ZG1m";
751 napi_value root = nullptr;
752 bool hasRoot = false;
753 napi_value global = nullptr;
754 napi_get_global(env, &global);
755 napi_has_named_property(env, global, rootPropName, &hasRoot);
756 if (hasRoot) {
757 napi_get_named_property(env, global, rootPropName, &root);
758 } else {
759 napi_create_object(env, &root);
760 napi_set_named_property(env, global, rootPropName, root);
761 }
762
763 std::string propName = "constructor_of_" + name;
764 napi_value constructor = nullptr;
765 bool hasProp = false;
766 napi_has_named_property(env, root, propName.c_str(), &hasProp);
767 if (hasProp) {
768 napi_get_named_property(env, root, propName.c_str(), &constructor);
769 if (constructor != nullptr) {
770 LOG_DEBUG(UDMF_KITS_NAPI, "got data.distributeddata.%{public}s as constructor", propName.c_str());
771 return constructor;
772 }
773 hasProp = false; // no constructor.
774 }
775
776 NAPI_CALL_BASE(env,
777 napi_define_class(env, name.c_str(), name.size(), newcb, nullptr, count, properties, &constructor),
778 nullptr);
779 NAPI_ASSERT(env, constructor != nullptr, "napi_define_class failed!");
780
781 if (!hasProp) {
782 napi_set_named_property(env, root, propName.c_str(), constructor);
783 LOG_DEBUG(UDMF_KITS_NAPI, "save constructor to data.distributeddata.%{public}s", propName.c_str());
784 }
785 return constructor;
786 }
787
GetOptionalNamedProperty(napi_env env,napi_value & obj,const std::string & key,napi_value & napiValue)788 napi_status NapiDataUtils::GetOptionalNamedProperty(napi_env env, napi_value &obj, const std::string &key,
789 napi_value &napiValue)
790 {
791 bool hasKey = false;
792 napi_status status = napi_has_named_property(env, obj, key.c_str(), &hasKey);
793 if (status != napi_ok) {
794 LOG_ERROR(UDMF_KITS_NAPI, "napi_has_named_property failed, name = %{public}s", key.c_str());
795 return status;
796 }
797 if (!hasKey) {
798 napiValue = nullptr;
799 return napi_ok;
800 }
801 status = napi_get_named_property(env, obj, key.c_str(), &napiValue);
802 if (status != napi_ok || napiValue == nullptr) {
803 LOG_ERROR(UDMF_KITS_NAPI, "napi_get_named_property failed, name = %{public}s", key.c_str());
804 return napi_generic_failure;
805 }
806 if (IsNull(env, napiValue)) {
807 napiValue = nullptr;
808 return napi_ok;
809 }
810 return napi_ok;
811 }
812 } // namespace UDMF
813 } // namespace OHOS
814