• 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 
16 #include "napi_data_utils.h"
17 
18 #include "napi_queue.h"
19 
20 namespace OHOS {
21 namespace UDMF {
22 constexpr int32_t STR_MAX_LENGTH = 4096;
23 constexpr size_t STR_TAIL_LENGTH = 1;
24 
25 /* napi_value <-> bool */
GetValue(napi_env env,napi_value in,bool & out)26 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, bool &out)
27 {
28     LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- bool");
29     return napi_get_value_bool(env, in, &out);
30 }
31 
SetValue(napi_env env,const bool & in,napi_value & out)32 napi_status NapiDataUtils::SetValue(napi_env env, const bool &in, napi_value &out)
33 {
34     LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> bool");
35     return napi_get_boolean(env, in, &out);
36 }
37 
38 /* napi_value <-> int32_t */
GetValue(napi_env env,napi_value in,int32_t & out)39 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, int32_t &out)
40 {
41     LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> int32_t");
42     return napi_get_value_int32(env, in, &out);
43 }
44 
SetValue(napi_env env,const int32_t & in,napi_value & out)45 napi_status NapiDataUtils::SetValue(napi_env env, const int32_t &in, napi_value &out)
46 {
47     LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- int32_t");
48     return napi_create_int32(env, in, &out);
49 }
50 
51 /* napi_value <-> int64_t */
GetValue(napi_env env,napi_value in,int64_t & out)52 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, int64_t &out)
53 {
54     LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> int64_t");
55     return napi_get_value_int64(env, in, &out);
56 }
57 
SetValue(napi_env env,const int64_t & in,napi_value & out)58 napi_status NapiDataUtils::SetValue(napi_env env, const int64_t &in, napi_value &out)
59 {
60     LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- int64_t");
61     return napi_create_int64(env, in, &out);
62 }
63 
64 /* napi_value <-> float */
GetValue(napi_env env,napi_value in,float & out)65 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, float &out)
66 {
67     LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> float");
68     double tmp;
69     napi_status status = napi_get_value_double(env, in, &tmp);
70     out = tmp;
71     return status;
72 }
73 
SetValue(napi_env env,const float & in,napi_value & out)74 napi_status NapiDataUtils::SetValue(napi_env env, const float &in, napi_value &out)
75 {
76     LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- float");
77     double tmp = in;
78     return napi_create_double(env, tmp, &out);
79 }
80 
81 /* napi_value <-> double */
GetValue(napi_env env,napi_value in,double & out)82 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, double &out)
83 {
84     LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> double");
85     return napi_get_value_double(env, in, &out);
86 }
87 
SetValue(napi_env env,const double & in,napi_value & out)88 napi_status NapiDataUtils::SetValue(napi_env env, const double &in, napi_value &out)
89 {
90     LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- double");
91     return napi_create_double(env, in, &out);
92 }
93 
94 /* napi_value <-> std::string */
GetValue(napi_env env,napi_value in,std::string & out)95 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, std::string &out)
96 {
97     size_t maxLen = STR_MAX_LENGTH;
98     napi_status status = napi_get_value_string_utf8(env, in, NULL, 0, &maxLen);
99     if (maxLen == 0) {
100         GET_AND_THROW_LAST_ERROR(env);
101         return status;
102     }
103     char *buf = new (std::nothrow) char[maxLen + STR_TAIL_LENGTH];
104     if (buf != nullptr) {
105         size_t len = 0;
106         status = napi_get_value_string_utf8(env, in, buf, maxLen + STR_TAIL_LENGTH, &len);
107         if (status != napi_ok) {
108             GET_AND_THROW_LAST_ERROR(env);
109         }
110         buf[len] = 0;
111         out = std::string(buf);
112         delete[] buf;
113     } else {
114         status = napi_generic_failure;
115     }
116     return status;
117 }
118 
SetValue(napi_env env,const std::string & in,napi_value & out)119 napi_status NapiDataUtils::SetValue(napi_env env, const std::string &in, napi_value &out)
120 {
121     LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- std::string %{public}d", (int)in.length());
122     return napi_create_string_utf8(env, in.c_str(), in.size(), &out);
123 }
124 
125 /* napi_value <-> std::vector<std::string> */
GetValue(napi_env env,napi_value in,std::vector<std::string> & out)126 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, std::vector<std::string> &out)
127 {
128     LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> std::vector<std::string>");
129     bool isArray = false;
130     napi_is_array(env, in, &isArray);
131     LOG_ERROR_RETURN(isArray, "not an array", napi_invalid_arg);
132 
133     uint32_t length = 0;
134     napi_status status = napi_get_array_length(env, in, &length);
135     LOG_ERROR_RETURN((status == napi_ok) && (length > 0), "get_array failed!", napi_invalid_arg);
136     for (uint32_t i = 0; i < length; ++i) {
137         napi_value item = nullptr;
138         status = napi_get_element(env, in, i, &item);
139         LOG_ERROR_RETURN((item != nullptr) && (status == napi_ok), "no element", napi_invalid_arg);
140         std::string value;
141         status = GetValue(env, item, value);
142         LOG_ERROR_RETURN(status == napi_ok, "not a string", napi_invalid_arg);
143         out.push_back(value);
144     }
145     return status;
146 }
147 
SetValue(napi_env env,const std::vector<std::string> & in,napi_value & out)148 napi_status NapiDataUtils::SetValue(napi_env env, const std::vector<std::string> &in, napi_value &out)
149 {
150     LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- std::vector<std::string>");
151     napi_status status = napi_create_array_with_length(env, in.size(), &out);
152     LOG_ERROR_RETURN(status == napi_ok, "create array failed!", status);
153     int index = 0;
154     for (auto &item : in) {
155         napi_value element = nullptr;
156         SetValue(env, item, element);
157         status = napi_set_element(env, out, index++, element);
158         LOG_ERROR_RETURN((status == napi_ok), "napi_set_element failed!", status);
159     }
160     return status;
161 }
162 
163 /* napi_value <-> std::vector<uint8_t> */
GetValue(napi_env env,napi_value in,std::vector<uint8_t> & out)164 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, std::vector<uint8_t> &out)
165 {
166     out.clear();
167     LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> std::vector<uint8_t> ");
168     napi_typedarray_type type = napi_biguint64_array;
169     size_t length = 0;
170     napi_value buffer = nullptr;
171     size_t offset = 0;
172     void *data = nullptr;
173     napi_status status = napi_get_typedarray_info(env, in, &type, &length, &data, &buffer, &offset);
174     LOG_DEBUG(UDMF_KITS_NAPI, "array type=%{public}d length=%{public}d offset=%{public}d  status=%{public}d",
175         (int)type, (int)length, (int)offset, status);
176     LOG_ERROR_RETURN(status == napi_ok, "napi_get_typedarray_info failed!", napi_invalid_arg);
177     LOG_ERROR_RETURN(type == napi_uint8_array, "is not Uint8Array!", napi_invalid_arg);
178     LOG_ERROR_RETURN((length > 0) && (data != nullptr), "invalid data!", napi_invalid_arg);
179     out.assign(reinterpret_cast<uint8_t *>(data), reinterpret_cast<uint8_t *>(data) + length);
180     return status;
181 }
182 
SetValue(napi_env env,const std::vector<uint8_t> & in,napi_value & out)183 napi_status NapiDataUtils::SetValue(napi_env env, const std::vector<uint8_t> &in, napi_value &out)
184 {
185     LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- std::vector<uint8_t> ");
186     LOG_ERROR_RETURN(in.size() > 0, "invalid std::vector<uint8_t>", napi_invalid_arg);
187     void *data = nullptr;
188     napi_value buffer = nullptr;
189     napi_status status = napi_create_arraybuffer(env, in.size(), &data, &buffer);
190     LOG_ERROR_RETURN((status == napi_ok), "create array buffer failed!", status);
191 
192     if (memcpy_s(data, in.size(), in.data(), in.size()) != EOK) {
193         LOG_ERROR(UDMF_KITS_NAPI, "memcpy_s not EOK");
194         return napi_invalid_arg;
195     }
196     status = napi_create_typedarray(env, napi_uint8_array, in.size(), buffer, 0, &out);
197     LOG_ERROR_RETURN((status == napi_ok), "napi_value <- std::vector<uint8_t> invalid value", status);
198     return status;
199 }
200 
201 /* napi_value <-> std::map<std::string, int32_t> */
GetValue(napi_env env,napi_value in,std::map<std::string,int32_t> & out)202 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, std::map<std::string, int32_t> &out)
203 {
204     LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> std::map<std::string, int32_t> ");
205     (void)(env);
206     (void)(in);
207     (void)(out);
208     LOG_ERROR_RETURN(false, "std::map<std::string, uint32_t> from napi_value, unsupported!", napi_invalid_arg);
209     return napi_invalid_arg;
210 }
211 
SetValue(napi_env env,const std::map<std::string,int32_t> & in,napi_value & out)212 napi_status NapiDataUtils::SetValue(napi_env env, const std::map<std::string, int32_t> &in, napi_value &out)
213 {
214     LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- std::map<std::string, int32_t> ");
215     napi_status status = napi_create_array_with_length(env, in.size(), &out);
216     LOG_ERROR_RETURN((status == napi_ok), "invalid object", status);
217     int index = 0;
218     for (const auto &[key, value] : in) {
219         napi_value element = nullptr;
220         napi_create_array_with_length(env, TUPLE_SIZE, &element);
221         napi_value jsKey = nullptr;
222         napi_create_string_utf8(env, key.c_str(), key.size(), &jsKey);
223         napi_set_element(env, element, TUPLE_KEY, jsKey);
224         napi_value jsValue = nullptr;
225         napi_create_int32(env, static_cast<int32_t>(value), &jsValue);
226         napi_set_element(env, element, TUPLE_VALUE, jsValue);
227         napi_set_element(env, out, index++, element);
228     }
229     return status;
230 }
231 
232 /* napi_value <-> std::map<std::string, int64_t> */
GetValue(napi_env env,napi_value in,std::map<std::string,int64_t> & out)233 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, std::map<std::string, int64_t> &out)
234 {
235     LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> std::map<std::string, int64_t> ");
236     (void)(env);
237     (void)(in);
238     (void)(out);
239     LOG_ERROR_RETURN(false, "std::map<std::string, int64_t> from napi_value, unsupported!", napi_invalid_arg);
240     return napi_invalid_arg;
241 }
242 
SetValue(napi_env env,const std::map<std::string,int64_t> & in,napi_value & out)243 napi_status NapiDataUtils::SetValue(napi_env env, const std::map<std::string, int64_t> &in, napi_value &out)
244 {
245     LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- std::map<std::string, int64_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_int64(env, static_cast<int64_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 <-> UDVariant */
GetValue(napi_env env,napi_value in,UDVariant & out)264 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, UDVariant &out)
265 {
266     napi_valuetype type = napi_undefined;
267     napi_status status = napi_typeof(env, in, &type);
268     LOG_ERROR_RETURN((status == napi_ok), "invalid type", status);
269     switch (type) {
270         case napi_boolean: {
271             bool vBool = false;
272             status = GetValue(env, in, vBool);
273             out = vBool;
274             break;
275         }
276         case napi_number: {
277             double vNum = 0.0f;
278             status = GetValue(env, in, vNum);
279             out = vNum;
280             break;
281         }
282         case napi_string: {
283             std::string vString;
284             status = GetValue(env, in, vString);
285             out = vString;
286             break;
287         }
288         case napi_object: {
289             std::vector<uint8_t> vct;
290             status = GetValue(env, in, vct);
291             out = vct;
292             break;
293         }
294         default:
295             LOG_ERROR(UDMF_KITS_NAPI,
296                 "napi_value <- UDVariant not [Uint8Array | string | boolean | number] type=%{public}d", type);
297             status = napi_invalid_arg;
298             break;
299     }
300     return status;
301 }
302 
SetValue(napi_env env,const UDVariant & in,napi_value & out)303 napi_status NapiDataUtils::SetValue(napi_env env, const UDVariant &in, napi_value &out)
304 {
305     auto strValue = std::get_if<std::string>(&in);
306     if (strValue != nullptr) {
307         return SetValue(env, *strValue, out);
308     }
309     auto intValue = std::get_if<int32_t>(&in);
310     if (intValue != nullptr) {
311         return SetValue(env, *intValue, out);
312     }
313     auto pUint8 = std::get_if<std::vector<uint8_t>>(&in);
314     if (pUint8 != nullptr) {
315         return SetValue(env, *pUint8, out);
316     }
317     auto boolValue = std::get_if<bool>(&in);
318     if (boolValue != nullptr) {
319         return SetValue(env, *boolValue, out);
320     }
321     auto dblValue = std::get_if<double>(&in);
322     if (dblValue != nullptr) {
323         return SetValue(env, *dblValue, out);
324     }
325 
326     LOG_ERROR(UDMF_KITS_NAPI, "napi_value <- UDVariant  INVALID value type");
327     return napi_invalid_arg;
328 }
329 
330 /* napi_value <-> UDDetails */
GetValue(napi_env env,napi_value in,UDDetails & out)331 napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, UDDetails &out)
332 {
333     if (!IsTypeForNapiValue(env, in, napi_object)) {
334         return napi_invalid_arg;
335     }
336     napi_value jsProNameList = nullptr;
337     uint32_t jsProCount = 0;
338 
339     NAPI_CALL_BASE(env, napi_get_property_names(env, in, &jsProNameList), napi_invalid_arg);
340     NAPI_CALL_BASE(env, napi_get_array_length(env, jsProNameList, &jsProCount), napi_invalid_arg);
341 
342     napi_value jsProName = nullptr;
343     napi_value jsProValue = nullptr;
344     for (uint32_t index = 0; index < jsProCount; index++) {
345         NAPI_CALL_BASE(env, napi_get_element(env, jsProNameList, index, &jsProName), napi_invalid_arg);
346         if (!IsTypeForNapiValue(env, jsProName, napi_string)) {
347             return napi_invalid_arg;
348         }
349         std::string strProName;
350         GetValue(env, jsProName, strProName);
351 
352         NAPI_CALL_BASE(env, napi_get_named_property(env, in, strProName.c_str(), &jsProValue), napi_invalid_arg);
353         UDVariant natValue;
354         GetValue(env, jsProValue, natValue);
355         out[strProName] = natValue;
356     }
357     return napi_ok;
358 }
359 
SetValue(napi_env env,const UDDetails & in,napi_value & out)360 napi_status NapiDataUtils::SetValue(napi_env env, const UDDetails &in, napi_value &out)
361 {
362     NAPI_CALL_BASE(env, napi_create_object(env, &out), napi_invalid_arg);
363     for (std::pair<std::string, UDVariant> prop : in) {
364         napi_value jsProValue = nullptr;
365         SetValue(env, prop.second, jsProValue);
366         NAPI_CALL_BASE(env, napi_set_named_property(env, out, prop.first.c_str(), jsProValue), napi_invalid_arg);
367     }
368     return napi_ok;
369 }
370 
IsTypeForNapiValue(napi_env env,napi_value param,napi_valuetype expectType)371 bool NapiDataUtils::IsTypeForNapiValue(napi_env env, napi_value param, napi_valuetype expectType)
372 {
373     napi_valuetype valueType = napi_undefined;
374 
375     if (param == nullptr) {
376         return false;
377     }
378 
379     if (napi_typeof(env, param, &valueType) != napi_ok) {
380         return false;
381     }
382 
383     return valueType == expectType;
384 }
385 
IsNull(napi_env env,napi_value value)386 bool NapiDataUtils::IsNull(napi_env env, napi_value value)
387 {
388     napi_valuetype type = napi_undefined;
389     napi_status status = napi_typeof(env, value, &type);
390     if (status == napi_ok && (type == napi_undefined || type == napi_null)) {
391         return true;
392     }
393     if (type == napi_string) {
394         size_t len;
395         napi_get_value_string_utf8(env, value, NULL, 0, &len);
396         return len == 0;
397     }
398     return false;
399 }
400 
DefineClass(napi_env env,const std::string & name,const napi_property_descriptor * properties,size_t count,napi_callback newcb)401 napi_value NapiDataUtils::DefineClass(napi_env env, const std::string &name,
402     const napi_property_descriptor *properties, size_t count, napi_callback newcb)
403 {
404     // base64("data.udmf") as rootPropName, i.e. global.<root>
405     const std::string rootPropName = "ZGF0YS51ZG1m";
406     napi_value root = nullptr;
407     bool hasRoot = false;
408     napi_value global = nullptr;
409     napi_get_global(env, &global);
410     napi_has_named_property(env, global, rootPropName.c_str(), &hasRoot);
411     if (hasRoot) {
412         napi_get_named_property(env, global, rootPropName.c_str(), &root);
413     } else {
414         napi_create_object(env, &root);
415         napi_set_named_property(env, global, rootPropName.c_str(), root);
416     }
417 
418     std::string propName = "constructor_of_" + name;
419     napi_value constructor = nullptr;
420     bool hasProp = false;
421     napi_has_named_property(env, root, propName.c_str(), &hasProp);
422     if (hasProp) {
423         napi_get_named_property(env, root, propName.c_str(), &constructor);
424         if (constructor != nullptr) {
425             LOG_DEBUG(UDMF_KITS_NAPI, "got data.distributeddata.%{public}s as constructor", propName.c_str());
426             return constructor;
427         }
428         hasProp = false; // no constructor.
429     }
430 
431     NAPI_CALL_BASE(env,
432         napi_define_class(env, name.c_str(), name.size(), newcb, nullptr, count, properties, &constructor),
433         nullptr);
434     NAPI_ASSERT(env, constructor != nullptr, "napi_define_class failed!");
435 
436     if (!hasProp) {
437         napi_set_named_property(env, root, propName.c_str(), constructor);
438         LOG_DEBUG(UDMF_KITS_NAPI, "save constructor to data.distributeddata.%{public}s", propName.c_str());
439     }
440     return constructor;
441 }
442 } // namespace UDMF
443 } // namespace OHOS
444