1 /*
2 * Copyright (c) 2022 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_parse_utils.h"
17
18 #include <sys/mman.h>
19 #include <unistd.h>
20 #include <regex>
21
22 #include "nweb.h"
23 #include "nweb_log.h"
24 #include "ohos_adapter_helper.h"
25 #include "securec.h"
26
27 #define MAX_FLOWBUF_DATA_SIZE 52428800 /* 50 MB */
28
29 namespace OHOS {
30 namespace NWeb {
31 namespace {
ConvertToNapiHandlerOfString(napi_env env,std::shared_ptr<NWebMessage> src,napi_value & dst)32 bool ConvertToNapiHandlerOfString(napi_env env, std::shared_ptr<NWebMessage> src, napi_value& dst)
33 {
34 std::string msgStr = src->GetString();
35 napi_create_string_utf8(env, msgStr.c_str(), msgStr.length(), &dst);
36 return true;
37 }
38
ConvertToNapiHandlerOfBinary(napi_env env,std::shared_ptr<NWebMessage> src,napi_value & dst)39 bool ConvertToNapiHandlerOfBinary(napi_env env, std::shared_ptr<NWebMessage> src, napi_value& dst)
40 {
41 std::vector<uint8_t> msgArr = src->GetBinary();
42 void *arrayData = nullptr;
43 napi_create_arraybuffer(env, msgArr.size(), &arrayData, &dst);
44 if (arrayData == nullptr) {
45 WVLOG_E("Create arraybuffer failed");
46 return false;
47 }
48 for (size_t i = 0; i < msgArr.size(); ++i) {
49 *(uint8_t*)((uint8_t*)arrayData + i) = msgArr[i];
50 }
51 return true;
52 }
53
ConvertToNapiHandlerOfBoolean(napi_env env,std::shared_ptr<NWebMessage> src,napi_value & dst)54 bool ConvertToNapiHandlerOfBoolean(napi_env env, std::shared_ptr<NWebMessage> src, napi_value& dst)
55 {
56 bool value = src->GetBoolean();
57 napi_get_boolean(env, value, &dst);
58 return true;
59 }
60
ConvertToNapiHandlerOfInteger(napi_env env,std::shared_ptr<NWebMessage> src,napi_value & dst)61 bool ConvertToNapiHandlerOfInteger(napi_env env, std::shared_ptr<NWebMessage> src, napi_value& dst)
62 {
63 int64_t value = src->GetInt64();
64 napi_create_int64(env, value, &dst);
65 return true;
66 }
67
ConvertToNapiHandlerOfDouble(napi_env env,std::shared_ptr<NWebMessage> src,napi_value & dst)68 bool ConvertToNapiHandlerOfDouble(napi_env env, std::shared_ptr<NWebMessage> src, napi_value& dst)
69 {
70 double value = src->GetDouble();
71 napi_create_double(env, value, &dst);
72 return true;
73 }
74
ConvertToNapiHandlerOfError(napi_env env,std::shared_ptr<NWebMessage> src,napi_value & dst)75 bool ConvertToNapiHandlerOfError(napi_env env, std::shared_ptr<NWebMessage> src, napi_value& dst)
76 {
77 std::string errorName = src->GetErrName();
78 std::string errorMsg = src->GetErrName() + ": " + src->GetErrMsg();
79 napi_value name = nullptr;
80 napi_value message = nullptr;
81 napi_create_string_utf8(env, errorName.c_str(), errorName.length(), &name);
82 napi_create_string_utf8(env, errorMsg.c_str(), errorMsg.length(), &message);
83 napi_create_error(env, name, message, &dst);
84 return true;
85 }
86
ConvertToNapiHandlerOfStringArray(napi_env env,std::shared_ptr<NWebMessage> src,napi_value & dst)87 bool ConvertToNapiHandlerOfStringArray(napi_env env, std::shared_ptr<NWebMessage> src, napi_value& dst)
88 {
89 std::vector<std::string> values = src->GetStringArray();
90 napi_create_array(env, &dst);
91 bool isArray = false;
92 if (napi_is_array(env, dst, &isArray) != napi_ok || !isArray) {
93 WVLOG_E("Create array failed");
94 return false;
95 }
96
97 int32_t index = 0;
98 for (auto value : values) {
99 napi_value element = nullptr;
100 napi_create_string_utf8(env, value.c_str(), value.length(), &element);
101 napi_set_element(env, dst, index++, element);
102 }
103 return true;
104 }
105
ConvertToNapiHandlerOfBooleanArray(napi_env env,std::shared_ptr<NWebMessage> src,napi_value & dst)106 bool ConvertToNapiHandlerOfBooleanArray(napi_env env, std::shared_ptr<NWebMessage> src, napi_value& dst)
107 {
108 std::vector<bool> values = src->GetBooleanArray();
109 napi_create_array(env, &dst);
110 bool isArray = false;
111 if (napi_is_array(env, dst, &isArray) != napi_ok || !isArray) {
112 WVLOG_E("Create array failed");
113 return false;
114 }
115
116 int32_t index = 0;
117 for (auto value : values) {
118 napi_value element = nullptr;
119 napi_get_boolean(env, value, &element);
120 napi_set_element(env, dst, index++, element);
121 }
122 return true;
123 }
124
ConvertToNapiHandlerOfDoubleArray(napi_env env,std::shared_ptr<NWebMessage> src,napi_value & dst)125 bool ConvertToNapiHandlerOfDoubleArray(napi_env env, std::shared_ptr<NWebMessage> src, napi_value& dst)
126 {
127 std::vector<double> values = src->GetDoubleArray();
128 napi_create_array(env, &dst);
129 bool isArray = false;
130 if (napi_is_array(env, dst, &isArray) != napi_ok || !isArray) {
131 WVLOG_E("Create array failed");
132 return false;
133 }
134
135 int32_t index = 0;
136 for (auto value : values) {
137 napi_value element = nullptr;
138 napi_create_double(env, value, &element);
139 napi_set_element(env, dst, index++, element);
140 }
141 return true;
142 }
143
ConvertToNapiHandlerOfInt64Array(napi_env env,std::shared_ptr<NWebMessage> src,napi_value & dst)144 bool ConvertToNapiHandlerOfInt64Array(napi_env env, std::shared_ptr<NWebMessage> src, napi_value& dst)
145 {
146 std::vector<int64_t> values = src->GetInt64Array();
147 napi_create_array(env, &dst);
148 bool isArray = false;
149 if (napi_is_array(env, dst, &isArray) != napi_ok || !isArray) {
150 WVLOG_E("Create array failed");
151 return false;
152 }
153
154 int32_t index = 0;
155 for (auto value : values) {
156 napi_value element = nullptr;
157 napi_create_int64(env, value, &element);
158 napi_set_element(env, dst, index++, element);
159 }
160 return true;
161 }
162 } // namespace
163
CreateEnumConstructor(napi_env env,napi_callback_info info)164 napi_value NapiParseUtils::CreateEnumConstructor(napi_env env, napi_callback_info info)
165 {
166 napi_value arg = nullptr;
167 napi_get_cb_info(env, info, nullptr, nullptr, &arg, nullptr);
168 return arg;
169 }
170
ToInt32Value(napi_env env,int32_t number)171 napi_value NapiParseUtils::ToInt32Value(napi_env env, int32_t number)
172 {
173 napi_value result = nullptr;
174 napi_create_int32(env, number, &result);
175 return result;
176 }
177
ParseInt32(napi_env env,napi_value argv,int32_t & outValue)178 bool NapiParseUtils::ParseInt32(napi_env env, napi_value argv, int32_t& outValue)
179 {
180 napi_valuetype valueType = napi_undefined;
181
182 napi_typeof(env, argv, &valueType);
183 if (valueType != napi_number) {
184 return false;
185 }
186
187 int32_t number = 0;
188 napi_get_value_int32(env, argv, &number);
189 outValue = number;
190
191 return true;
192 }
193
ParseUint32(napi_env env,napi_value argv,uint32_t & outValue)194 bool NapiParseUtils::ParseUint32(napi_env env, napi_value argv, uint32_t& outValue)
195 {
196 napi_valuetype valueType = napi_undefined;
197
198 napi_typeof(env, argv, &valueType);
199 if (valueType != napi_number) {
200 return false;
201 }
202
203 uint32_t number = 0;
204 napi_get_value_uint32(env, argv, &number);
205 outValue = number;
206
207 return true;
208 }
209
ParseUint64(napi_env env,napi_value argv,uint64_t & outValue,bool * lossless)210 bool NapiParseUtils::ParseUint64(napi_env env, napi_value argv, uint64_t& outValue, bool *lossless)
211 {
212 napi_valuetype valueType = napi_undefined;
213
214 napi_typeof(env, argv, &valueType);
215 if (valueType != napi_bigint) {
216 return false;
217 }
218
219 uint64_t number = 0;
220 napi_get_value_bigint_uint64(env, argv, &number, lossless);
221 outValue = number;
222
223 return true;
224 }
225
ParseInt64(napi_env env,napi_value argv,int64_t & outValue)226 bool NapiParseUtils::ParseInt64(napi_env env, napi_value argv, int64_t& outValue)
227 {
228 napi_valuetype valueType = napi_undefined;
229
230 napi_typeof(env, argv, &valueType);
231 if (valueType != napi_number) {
232 return false;
233 }
234
235 int64_t number = 0;
236 napi_get_value_int64(env, argv, &number);
237 outValue = number;
238
239 return true;
240 }
241
ParseString(napi_env env,napi_value argv,std::string & outValue)242 bool NapiParseUtils::ParseString(napi_env env, napi_value argv, std::string& outValue)
243 {
244 size_t bufferSize = 0;
245 napi_valuetype valueType = napi_undefined;
246
247 napi_typeof(env, argv, &valueType);
248 if (valueType != napi_string) {
249 WVLOG_E("Not a valid napi string");
250 return false;
251 }
252 napi_get_value_string_utf8(env, argv, nullptr, 0, &bufferSize);
253 if (bufferSize + 1 > UINT_MAX) {
254 WVLOG_E("String length is too long");
255 return false;
256 }
257 size_t jsStringLength = 0;
258 outValue.resize(bufferSize);
259 napi_get_value_string_utf8(env, argv, outValue.data(), bufferSize + 1, &jsStringLength);
260 if (jsStringLength != bufferSize) {
261 WVLOG_E("The length values obtained twice are different");
262 return false;
263 }
264 return true;
265 }
266
ParseArrayBuffer(napi_env env,napi_value argv,std::string & outValue)267 bool NapiParseUtils::ParseArrayBuffer(napi_env env, napi_value argv, std::string& outValue)
268 {
269 bool isArrayBuffer = false;
270 if (napi_ok != napi_is_arraybuffer(env, argv, &isArrayBuffer) || !isArrayBuffer) {
271 WVLOG_E("Not a valid napi ArrayBuffer");
272 return false;
273 }
274
275 char *arrBuf = nullptr;
276 size_t byteLength = 0;
277 napi_get_arraybuffer_info(env, argv, (void**)&arrBuf, &byteLength);
278 if (!arrBuf) {
279 WVLOG_E("Get arrayBuffer info failed");
280 return false;
281 }
282 outValue = std::string(arrBuf, byteLength);
283 return true;
284 }
285
ParseBoolean(napi_env env,napi_value argv,bool & outValue)286 bool NapiParseUtils::ParseBoolean(napi_env env, napi_value argv, bool& outValue)
287 {
288 napi_valuetype valueType = napi_null;
289
290 napi_typeof(env, argv, &valueType);
291 if (valueType != napi_boolean) {
292 return false;
293 }
294
295 bool boolValue;
296 napi_get_value_bool(env, argv, &boolValue);
297 outValue = boolValue;
298 return true;
299 }
300
ParseStringArray(napi_env env,napi_value argv,std::vector<std::string> & outValue)301 bool NapiParseUtils::ParseStringArray(napi_env env, napi_value argv, std::vector<std::string>& outValue)
302 {
303 bool isArray = false;
304 napi_is_array(env, argv, &isArray);
305 if (!isArray) {
306 return false;
307 }
308
309 uint32_t arrLen = 0;
310 napi_get_array_length(env, argv, &arrLen);
311 for (uint32_t i = 0; i < arrLen; ++i) {
312 napi_value item = nullptr;
313 napi_get_element(env, argv, i, &item);
314
315 std::string str;
316 if (ParseString(env, item, str)) {
317 outValue.push_back(str);
318 }
319 }
320
321 return true;
322 }
323
ParseInt64Array(napi_env env,napi_value argv,std::vector<int64_t> & outValue)324 bool NapiParseUtils::ParseInt64Array(napi_env env, napi_value argv, std::vector<int64_t>& outValue)
325 {
326 bool isArray = false;
327 napi_is_array(env, argv, &isArray);
328 if (!isArray) {
329 return false;
330 }
331
332 uint32_t arrLen = 0;
333 napi_get_array_length(env, argv, &arrLen);
334 for (uint32_t i = 0; i < arrLen; ++i) {
335 napi_value item = nullptr;
336 napi_get_element(env, argv, i, &item);
337
338 int64_t value;
339 if (ParseInt64(env, item, value)) {
340 outValue.push_back(value);
341 }
342 }
343
344 return true;
345 }
346
ParseBooleanArray(napi_env env,napi_value argv,std::vector<bool> & outValue)347 bool NapiParseUtils::ParseBooleanArray(napi_env env, napi_value argv, std::vector<bool>& outValue)
348 {
349 bool isArray = false;
350 napi_is_array(env, argv, &isArray);
351 if (!isArray) {
352 return false;
353 }
354
355 uint32_t arrLen = 0;
356 napi_get_array_length(env, argv, &arrLen);
357 for (uint32_t i = 0; i < arrLen; ++i) {
358 napi_value item = nullptr;
359 napi_get_element(env, argv, i, &item);
360
361 bool value;
362 if (ParseBoolean(env, item, value)) {
363 outValue.push_back(value);
364 }
365 }
366
367 return true;
368 }
369
ParseDoubleArray(napi_env env,napi_value argv,std::vector<double> & outValue)370 bool NapiParseUtils::ParseDoubleArray(napi_env env, napi_value argv, std::vector<double>& outValue)
371 {
372 bool isArray = false;
373 napi_is_array(env, argv, &isArray);
374 if (!isArray) {
375 return false;
376 }
377
378 uint32_t arrLen = 0;
379 napi_get_array_length(env, argv, &arrLen);
380 for (uint32_t i = 0; i < arrLen; ++i) {
381 napi_value item = nullptr;
382 napi_get_element(env, argv, i, &item);
383
384 double value;
385 if (ParseDouble(env, item, value)) {
386 outValue.push_back(value);
387 }
388 }
389
390 return true;
391 }
392
ParseFloat(napi_env env,napi_value argv,float & outValue)393 bool NapiParseUtils::ParseFloat(napi_env env, napi_value argv, float& outValue)
394 {
395 napi_valuetype valueType = napi_undefined;
396 napi_typeof(env, argv, &valueType);
397 if (valueType != napi_number) {
398 return false;
399 }
400
401 double value;
402 napi_get_value_double(env, argv, &value);
403 outValue = static_cast<float>(value);
404 return true;
405 }
406
ParseDouble(napi_env env,napi_value argv,double & outValue)407 bool NapiParseUtils::ParseDouble(napi_env env, napi_value argv, double& outValue)
408 {
409 napi_valuetype valueType = napi_undefined;
410 napi_typeof(env, argv, &valueType);
411 if (valueType != napi_number) {
412 return false;
413 }
414
415 double value;
416 napi_get_value_double(env, argv, &value);
417 outValue = value;
418 return true;
419 }
420
421 //static
ConvertNWebToNapiValue(napi_env env,std::shared_ptr<NWebMessage> src,napi_value & dst)422 bool NapiParseUtils::ConvertNWebToNapiValue(napi_env env, std::shared_ptr<NWebMessage> src, napi_value& dst)
423 {
424 if (!src) {
425 WVLOG_E("src is nullptr");
426 return false;
427 }
428 NWebValue::Type type = src->GetType();
429 using ConvertNWebToNapiValueHandler = std::function<bool(napi_env, std::shared_ptr<NWebMessage>, napi_value&)>;
430 static const std::unordered_map<NWebValue::Type, ConvertNWebToNapiValueHandler> functionMap = {
431 { NWebValue::Type::STRING, ConvertToNapiHandlerOfString },
432 { NWebValue::Type::BINARY, ConvertToNapiHandlerOfBinary },
433 { NWebValue::Type::BOOLEAN, ConvertToNapiHandlerOfBoolean },
434 { NWebValue::Type::INTEGER, ConvertToNapiHandlerOfInteger },
435 { NWebValue::Type::DOUBLE, ConvertToNapiHandlerOfDouble },
436 { NWebValue::Type::ERROR, ConvertToNapiHandlerOfError },
437 { NWebValue::Type::STRINGARRAY, ConvertToNapiHandlerOfStringArray },
438 { NWebValue::Type::BOOLEANARRAY, ConvertToNapiHandlerOfBooleanArray },
439 { NWebValue::Type::DOUBLEARRAY, ConvertToNapiHandlerOfDoubleArray },
440 { NWebValue::Type::INT64ARRAY, ConvertToNapiHandlerOfInt64Array }
441 };
442 auto it = functionMap.find(type);
443 if (it == functionMap.end()) {
444 WVLOG_E("This type not support");
445 std::string msgStr = "This type not support";
446 napi_create_string_utf8(env, msgStr.c_str(), msgStr.length(), &dst);
447 return true;
448 }
449 return it->second(env, src, dst);
450 }
451
IsFormatStringOfLength(const std::string & str)452 bool IsFormatStringOfLength(const std::string &str)
453 {
454 std::regex pattern("^\\d+(px|vp|%)?$");
455 return std::regex_match(str, pattern);
456 }
457
IsNumberOfLength(const std::string & value)458 bool IsNumberOfLength(const std::string &value)
459 {
460 if (value.empty()) {
461 return false;
462 }
463 return std::all_of(value.begin(), value.end(), [](char i) { return isdigit(i); });
464 }
465
ParseJsLengthStringToInt(const std::string & input,PixelUnit & type,int32_t & value)466 bool NapiParseUtils::ParseJsLengthStringToInt(const std::string &input, PixelUnit &type, int32_t &value)
467 {
468 if (input.empty() || input.size() >= MAX_STRING_TO_INT32_LENGTH) {
469 return false;
470 }
471 if (!IsFormatStringOfLength(input)) {
472 return false;
473 }
474 if (IsNumberOfLength(input)) {
475 try {
476 value = std::stoi(input);
477 } catch (std::out_of_range&) {
478 WVLOG_E("input trans failed: out of range");
479 value = 0;
480 }
481 type = PixelUnit::VP;
482 return true;
483 }
484 if (input.back() == '%') {
485 std::string trans = input.substr(0, input.length() - 1);
486 if (IsNumberOfLength(trans)) {
487 try {
488 value = std::stoi(trans);
489 } catch (std::out_of_range&) {
490 WVLOG_E("input trans failed: out of range");
491 value = 0;
492 }
493 type = PixelUnit::PERCENTAGE;
494 return true;
495 }
496 return false;
497 }
498 if (input.length() < INTEGER_THREE) {
499 return false;
500 }
501 std::string lastTwo = input.substr(input.length() - INTEGER_TWO);
502 std::string trans = input.substr(0, input.length() - INTEGER_TWO);
503 if (!IsNumberOfLength(trans)) {
504 return false;
505 }
506 if (lastTwo == "px") {
507 try {
508 value = std::stoi(trans);
509 } catch (std::out_of_range&) {
510 WVLOG_E("input trans failed: out of range");
511 value = 0;
512 }
513 type = PixelUnit::PX;
514 return true;
515 } else if (lastTwo == "vp") {
516 try {
517 value = std::stoi(trans);
518 } catch (std::out_of_range&) {
519 WVLOG_E("input trans failed: out of range");
520 value = 0;
521 }
522 type = PixelUnit::VP;
523 return true;
524 }
525 return false;
526 }
527
ConstructStringFlowbuf(napi_env env,napi_value argv,int & fd,size_t & scriptLength)528 ErrCode NapiParseUtils::ConstructStringFlowbuf(napi_env env, napi_value argv, int& fd, size_t& scriptLength)
529 {
530 napi_valuetype valueType = napi_undefined;
531 napi_typeof(env, argv, &valueType);
532 if (valueType != napi_string) {
533 WVLOG_E("Not a valid napi string");
534 return NWebError::PARAM_CHECK_ERROR;
535 }
536
537 napi_get_value_string_utf8(env, argv, nullptr, 0, &scriptLength);
538 if (scriptLength + 1 > MAX_FLOWBUF_DATA_SIZE) {
539 WVLOG_E("String length is too long");
540 return NWebError::PARAM_CHECK_ERROR;
541 }
542
543 // get ashmem
544 auto flowbufferAdapter = OhosAdapterHelper::GetInstance().CreateFlowbufferAdapter();
545 if (!flowbufferAdapter) {
546 WVLOG_E("Create flowbuffer adapter failed");
547 return NWebError::NEW_OOM;
548 }
549 auto ashmem = flowbufferAdapter->CreateAshmem(scriptLength + 1, PROT_READ | PROT_WRITE, fd);
550 if (!ashmem) {
551 return NWebError::NEW_OOM;
552 }
553
554 // write to ashmem
555 size_t jsStringLength = 0;
556 napi_get_value_string_utf8(env, argv, static_cast<char*>(ashmem), scriptLength + 1, &jsStringLength);
557 if (jsStringLength != scriptLength) {
558 close(fd);
559 WVLOG_E("Write js string failed, the length values are different");
560 return NWebError::PARAM_CHECK_ERROR;
561 }
562 return NWebError::NO_ERROR;
563 }
564
ConstructArrayBufFlowbuf(napi_env env,napi_value argv,int & fd,size_t & scriptLength)565 ErrCode NapiParseUtils::ConstructArrayBufFlowbuf(napi_env env, napi_value argv, int& fd, size_t& scriptLength)
566 {
567 bool isArrayBuffer = false;
568 if (napi_ok != napi_is_arraybuffer(env, argv, &isArrayBuffer) || !isArrayBuffer) {
569 WVLOG_E("Not a valid napi ArrayBuffer");
570 return NWebError::PARAM_CHECK_ERROR;
571 }
572
573 char *arrBuf = nullptr;
574 napi_get_arraybuffer_info(env, argv, (void**)&arrBuf, &scriptLength);
575 if (!arrBuf) {
576 WVLOG_E("Get arrayBuffer info failed");
577 return NWebError::PARAM_CHECK_ERROR;
578 }
579
580 if (scriptLength + 1 > MAX_FLOWBUF_DATA_SIZE) {
581 WVLOG_E("Arraybuffer length is too long");
582 return NWebError::PARAM_CHECK_ERROR;
583 }
584
585 // get ashmem
586 auto flowbufferAdapter = OhosAdapterHelper::GetInstance().CreateFlowbufferAdapter();
587 if (!flowbufferAdapter) {
588 WVLOG_E("Create flowbuffer adapter failed");
589 return NWebError::NEW_OOM;
590 }
591 auto ashmem = flowbufferAdapter->CreateAshmem(scriptLength + 1, PROT_READ | PROT_WRITE, fd);
592 if (!ashmem) {
593 return NWebError::NEW_OOM;
594 }
595
596 // write to ashmem
597 if (memcpy_s(ashmem, scriptLength + 1, arrBuf, scriptLength) != EOK) {
598 WVLOG_E("ConstructArrayBufFlowbuf, memory copy failed");
599 return NWebError::NEW_OOM;
600 }
601 static_cast<char*>(ashmem)[scriptLength] = '\0';
602 return NWebError::NO_ERROR;
603 }
604 } // namespace NWeb
605 } // namespace OHOS
606