• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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