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 29namespace OHOS { 30namespace NWeb { 31namespace { 32bool 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 39bool 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_status status = napi_create_arraybuffer(env, msgArr.size(), &arrayData, &dst); 44 if (status != napi_ok) { 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 54bool 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 61bool 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 68bool 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 75bool 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 87bool 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 106bool 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 125bool 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 144bool 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 164napi_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 171napi_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 178bool 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 194bool 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 210bool 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 226bool 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 242bool 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 267bool 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 286bool 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 301bool 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 324bool 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 347bool 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 370bool 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 393bool 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 407bool 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 422bool 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 452bool IsFormatStringOfLength(const std::string &str) 453{ 454 std::regex pattern("^\\d+(px|vp|%)?$"); 455 return std::regex_match(str, pattern); 456} 457 458bool 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 466bool NapiParseUtils::ParseJsLengthStringToInt(const std::string &input, PixelUnit &type, int32_t &value) 467{ 468 if (input.empty()) { 469 return false; 470 } 471 if (!IsFormatStringOfLength(input)) { 472 return false; 473 } 474 if (IsNumberOfLength(input)) { 475 value = std::stoi(input); 476 type = PixelUnit::VP; 477 return true; 478 } 479 if (input.back() == '%') { 480 std::string trans = input.substr(0, input.length() - 1); 481 if (IsNumberOfLength(trans)) { 482 value = std::stoi(trans); 483 type = PixelUnit::PERCENTAGE; 484 return true; 485 } 486 return false; 487 } 488 if (input.length() < INTEGER_THREE) { 489 return false; 490 } 491 std::string lastTwo = input.substr(input.length() - INTEGER_TWO); 492 std::string trans = input.substr(0, input.length() - INTEGER_TWO); 493 if (!IsNumberOfLength(trans)) { 494 return false; 495 } 496 if (lastTwo == "px") { 497 value = std::stoi(trans); 498 type = PixelUnit::PX; 499 return true; 500 } else if (lastTwo == "vp") { 501 value = std::stoi(trans); 502 type = PixelUnit::VP; 503 return true; 504 } 505 return false; 506} 507 508ErrCode NapiParseUtils::ConstructStringFlowbuf(napi_env env, napi_value argv, int& fd, size_t& scriptLength) 509{ 510 napi_valuetype valueType = napi_undefined; 511 napi_typeof(env, argv, &valueType); 512 if (valueType != napi_string) { 513 WVLOG_E("Not a valid napi string"); 514 return NWebError::PARAM_CHECK_ERROR; 515 } 516 517 napi_get_value_string_utf8(env, argv, nullptr, 0, &scriptLength); 518 if (scriptLength + 1 > MAX_FLOWBUF_DATA_SIZE) { 519 WVLOG_E("String length is too long"); 520 return NWebError::PARAM_CHECK_ERROR; 521 } 522 523 // get ashmem 524 auto flowbufferAdapter = OhosAdapterHelper::GetInstance().CreateFlowbufferAdapter(); 525 if (!flowbufferAdapter) { 526 WVLOG_E("Create flowbuffer adapter failed"); 527 return NWebError::NEW_OOM; 528 } 529 auto ashmem = flowbufferAdapter->CreateAshmem(scriptLength + 1, PROT_READ | PROT_WRITE, fd); 530 if (!ashmem) { 531 return NWebError::NEW_OOM; 532 } 533 534 // write to ashmem 535 size_t jsStringLength = 0; 536 napi_get_value_string_utf8(env, argv, static_cast<char*>(ashmem), scriptLength + 1, &jsStringLength); 537 if (jsStringLength != scriptLength) { 538 close(fd); 539 WVLOG_E("Write js string failed, the length values are different"); 540 return NWebError::PARAM_CHECK_ERROR; 541 } 542 return NWebError::NO_ERROR; 543} 544 545ErrCode NapiParseUtils::ConstructArrayBufFlowbuf(napi_env env, napi_value argv, int& fd, size_t& scriptLength) 546{ 547 bool isArrayBuffer = false; 548 if (napi_ok != napi_is_arraybuffer(env, argv, &isArrayBuffer) || !isArrayBuffer) { 549 WVLOG_E("Not a valid napi ArrayBuffer"); 550 return NWebError::PARAM_CHECK_ERROR; 551 } 552 553 char *arrBuf = nullptr; 554 napi_get_arraybuffer_info(env, argv, (void**)&arrBuf, &scriptLength); 555 if (!arrBuf) { 556 WVLOG_E("Get arrayBuffer info failed"); 557 return NWebError::PARAM_CHECK_ERROR; 558 } 559 560 if (scriptLength + 1 > MAX_FLOWBUF_DATA_SIZE) { 561 WVLOG_E("Arraybuffer length is too long"); 562 return NWebError::PARAM_CHECK_ERROR; 563 } 564 565 // get ashmem 566 auto flowbufferAdapter = OhosAdapterHelper::GetInstance().CreateFlowbufferAdapter(); 567 if (!flowbufferAdapter) { 568 WVLOG_E("Create flowbuffer adapter failed"); 569 return NWebError::NEW_OOM; 570 } 571 auto ashmem = flowbufferAdapter->CreateAshmem(scriptLength + 1, PROT_READ | PROT_WRITE, fd); 572 if (!ashmem) { 573 return NWebError::NEW_OOM; 574 } 575 576 // write to ashmem 577 if (memcpy_s(ashmem, scriptLength + 1, arrBuf, scriptLength) != EOK) { 578 WVLOG_E("ConstructArrayBufFlowbuf, memory copy failed"); 579 return NWebError::NEW_OOM; 580 } 581 static_cast<char*>(ashmem)[scriptLength] = '\0'; 582 return NWebError::NO_ERROR; 583} 584} // namespace NWeb 585} // namespace OHOS 586