/* * Copyright (c) 2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "napi_parse_utils.h" #include #include #include #include "nweb.h" #include "nweb_log.h" #include "ohos_adapter_helper.h" #include "securec.h" #define MAX_FLOWBUF_DATA_SIZE 52428800 /* 50 MB */ namespace OHOS { namespace NWeb { namespace { bool ConvertToNapiHandlerOfString(napi_env env, std::shared_ptr src, napi_value& dst) { std::string msgStr = src->GetString(); napi_create_string_utf8(env, msgStr.c_str(), msgStr.length(), &dst); return true; } bool ConvertToNapiHandlerOfBinary(napi_env env, std::shared_ptr src, napi_value& dst) { std::vector msgArr = src->GetBinary(); void *arrayData = nullptr; napi_create_arraybuffer(env, msgArr.size(), &arrayData, &dst); if (arrayData == nullptr) { WVLOG_E("Create arraybuffer failed"); return false; } for (size_t i = 0; i < msgArr.size(); ++i) { *(uint8_t*)((uint8_t*)arrayData + i) = msgArr[i]; } return true; } bool ConvertToNapiHandlerOfBoolean(napi_env env, std::shared_ptr src, napi_value& dst) { bool value = src->GetBoolean(); napi_get_boolean(env, value, &dst); return true; } bool ConvertToNapiHandlerOfInteger(napi_env env, std::shared_ptr src, napi_value& dst) { int64_t value = src->GetInt64(); napi_create_int64(env, value, &dst); return true; } bool ConvertToNapiHandlerOfDouble(napi_env env, std::shared_ptr src, napi_value& dst) { double value = src->GetDouble(); napi_create_double(env, value, &dst); return true; } bool ConvertToNapiHandlerOfError(napi_env env, std::shared_ptr src, napi_value& dst) { std::string errorName = src->GetErrName(); std::string errorMsg = src->GetErrName() + ": " + src->GetErrMsg(); napi_value name = nullptr; napi_value message = nullptr; napi_create_string_utf8(env, errorName.c_str(), errorName.length(), &name); napi_create_string_utf8(env, errorMsg.c_str(), errorMsg.length(), &message); napi_create_error(env, name, message, &dst); return true; } bool ConvertToNapiHandlerOfStringArray(napi_env env, std::shared_ptr src, napi_value& dst) { std::vector values = src->GetStringArray(); napi_create_array(env, &dst); bool isArray = false; if (napi_is_array(env, dst, &isArray) != napi_ok || !isArray) { WVLOG_E("Create array failed"); return false; } int32_t index = 0; for (auto value : values) { napi_value element = nullptr; napi_create_string_utf8(env, value.c_str(), value.length(), &element); napi_set_element(env, dst, index++, element); } return true; } bool ConvertToNapiHandlerOfBooleanArray(napi_env env, std::shared_ptr src, napi_value& dst) { std::vector values = src->GetBooleanArray(); napi_create_array(env, &dst); bool isArray = false; if (napi_is_array(env, dst, &isArray) != napi_ok || !isArray) { WVLOG_E("Create array failed"); return false; } int32_t index = 0; for (auto value : values) { napi_value element = nullptr; napi_get_boolean(env, value, &element); napi_set_element(env, dst, index++, element); } return true; } bool ConvertToNapiHandlerOfDoubleArray(napi_env env, std::shared_ptr src, napi_value& dst) { std::vector values = src->GetDoubleArray(); napi_create_array(env, &dst); bool isArray = false; if (napi_is_array(env, dst, &isArray) != napi_ok || !isArray) { WVLOG_E("Create array failed"); return false; } int32_t index = 0; for (auto value : values) { napi_value element = nullptr; napi_create_double(env, value, &element); napi_set_element(env, dst, index++, element); } return true; } bool ConvertToNapiHandlerOfInt64Array(napi_env env, std::shared_ptr src, napi_value& dst) { std::vector values = src->GetInt64Array(); napi_create_array(env, &dst); bool isArray = false; if (napi_is_array(env, dst, &isArray) != napi_ok || !isArray) { WVLOG_E("Create array failed"); return false; } int32_t index = 0; for (auto value : values) { napi_value element = nullptr; napi_create_int64(env, value, &element); napi_set_element(env, dst, index++, element); } return true; } } // namespace napi_value NapiParseUtils::CreateEnumConstructor(napi_env env, napi_callback_info info) { napi_value arg = nullptr; napi_get_cb_info(env, info, nullptr, nullptr, &arg, nullptr); return arg; } napi_value NapiParseUtils::ToInt32Value(napi_env env, int32_t number) { napi_value result = nullptr; napi_create_int32(env, number, &result); return result; } bool NapiParseUtils::ParseInt32(napi_env env, napi_value argv, int32_t& outValue) { napi_valuetype valueType = napi_undefined; napi_typeof(env, argv, &valueType); if (valueType != napi_number) { return false; } int32_t number = 0; napi_get_value_int32(env, argv, &number); outValue = number; return true; } bool NapiParseUtils::ParseUint32(napi_env env, napi_value argv, uint32_t& outValue) { napi_valuetype valueType = napi_undefined; napi_typeof(env, argv, &valueType); if (valueType != napi_number) { return false; } uint32_t number = 0; napi_get_value_uint32(env, argv, &number); outValue = number; return true; } bool NapiParseUtils::ParseUint64(napi_env env, napi_value argv, uint64_t& outValue, bool *lossless) { napi_valuetype valueType = napi_undefined; napi_typeof(env, argv, &valueType); if (valueType != napi_bigint) { return false; } uint64_t number = 0; napi_get_value_bigint_uint64(env, argv, &number, lossless); outValue = number; return true; } bool NapiParseUtils::ParseInt64(napi_env env, napi_value argv, int64_t& outValue) { napi_valuetype valueType = napi_undefined; napi_typeof(env, argv, &valueType); if (valueType != napi_number) { return false; } int64_t number = 0; napi_get_value_int64(env, argv, &number); outValue = number; return true; } bool NapiParseUtils::ParseString(napi_env env, napi_value argv, std::string& outValue) { size_t bufferSize = 0; napi_valuetype valueType = napi_undefined; napi_typeof(env, argv, &valueType); if (valueType != napi_string) { WVLOG_E("Not a valid napi string"); return false; } napi_get_value_string_utf8(env, argv, nullptr, 0, &bufferSize); if (bufferSize + 1 > UINT_MAX) { WVLOG_E("String length is too long"); return false; } size_t jsStringLength = 0; outValue.resize(bufferSize); napi_get_value_string_utf8(env, argv, outValue.data(), bufferSize + 1, &jsStringLength); if (jsStringLength != bufferSize) { WVLOG_E("The length values obtained twice are different"); return false; } return true; } bool NapiParseUtils::ParseArrayBuffer(napi_env env, napi_value argv, std::string& outValue) { bool isArrayBuffer = false; if (napi_ok != napi_is_arraybuffer(env, argv, &isArrayBuffer) || !isArrayBuffer) { WVLOG_E("Not a valid napi ArrayBuffer"); return false; } char *arrBuf = nullptr; size_t byteLength = 0; napi_get_arraybuffer_info(env, argv, (void**)&arrBuf, &byteLength); if (!arrBuf) { WVLOG_E("Get arrayBuffer info failed"); return false; } outValue = std::string(arrBuf, byteLength); return true; } bool NapiParseUtils::ParseBoolean(napi_env env, napi_value argv, bool& outValue) { napi_valuetype valueType = napi_null; napi_typeof(env, argv, &valueType); if (valueType != napi_boolean) { return false; } bool boolValue; napi_get_value_bool(env, argv, &boolValue); outValue = boolValue; return true; } bool NapiParseUtils::ParseStringArray(napi_env env, napi_value argv, std::vector& outValue) { bool isArray = false; napi_is_array(env, argv, &isArray); if (!isArray) { return false; } uint32_t arrLen = 0; napi_get_array_length(env, argv, &arrLen); for (uint32_t i = 0; i < arrLen; ++i) { napi_value item = nullptr; napi_get_element(env, argv, i, &item); std::string str; if (ParseString(env, item, str)) { outValue.push_back(str); } } return true; } bool NapiParseUtils::ParseInt64Array(napi_env env, napi_value argv, std::vector& outValue) { bool isArray = false; napi_is_array(env, argv, &isArray); if (!isArray) { return false; } uint32_t arrLen = 0; napi_get_array_length(env, argv, &arrLen); for (uint32_t i = 0; i < arrLen; ++i) { napi_value item = nullptr; napi_get_element(env, argv, i, &item); int64_t value; if (ParseInt64(env, item, value)) { outValue.push_back(value); } } return true; } bool NapiParseUtils::ParseBooleanArray(napi_env env, napi_value argv, std::vector& outValue) { bool isArray = false; napi_is_array(env, argv, &isArray); if (!isArray) { return false; } uint32_t arrLen = 0; napi_get_array_length(env, argv, &arrLen); for (uint32_t i = 0; i < arrLen; ++i) { napi_value item = nullptr; napi_get_element(env, argv, i, &item); bool value; if (ParseBoolean(env, item, value)) { outValue.push_back(value); } } return true; } bool NapiParseUtils::ParseDoubleArray(napi_env env, napi_value argv, std::vector& outValue) { bool isArray = false; napi_is_array(env, argv, &isArray); if (!isArray) { return false; } uint32_t arrLen = 0; napi_get_array_length(env, argv, &arrLen); for (uint32_t i = 0; i < arrLen; ++i) { napi_value item = nullptr; napi_get_element(env, argv, i, &item); double value; if (ParseDouble(env, item, value)) { outValue.push_back(value); } } return true; } bool NapiParseUtils::ParseFloat(napi_env env, napi_value argv, float& outValue) { napi_valuetype valueType = napi_undefined; napi_typeof(env, argv, &valueType); if (valueType != napi_number) { return false; } double value; napi_get_value_double(env, argv, &value); outValue = static_cast(value); return true; } bool NapiParseUtils::ParseDouble(napi_env env, napi_value argv, double& outValue) { napi_valuetype valueType = napi_undefined; napi_typeof(env, argv, &valueType); if (valueType != napi_number) { return false; } double value; napi_get_value_double(env, argv, &value); outValue = value; return true; } //static bool NapiParseUtils::ConvertNWebToNapiValue(napi_env env, std::shared_ptr src, napi_value& dst) { if (!src) { WVLOG_E("src is nullptr"); return false; } NWebValue::Type type = src->GetType(); using ConvertNWebToNapiValueHandler = std::function, napi_value&)>; static const std::unordered_map functionMap = { { NWebValue::Type::STRING, ConvertToNapiHandlerOfString }, { NWebValue::Type::BINARY, ConvertToNapiHandlerOfBinary }, { NWebValue::Type::BOOLEAN, ConvertToNapiHandlerOfBoolean }, { NWebValue::Type::INTEGER, ConvertToNapiHandlerOfInteger }, { NWebValue::Type::DOUBLE, ConvertToNapiHandlerOfDouble }, { NWebValue::Type::ERROR, ConvertToNapiHandlerOfError }, { NWebValue::Type::STRINGARRAY, ConvertToNapiHandlerOfStringArray }, { NWebValue::Type::BOOLEANARRAY, ConvertToNapiHandlerOfBooleanArray }, { NWebValue::Type::DOUBLEARRAY, ConvertToNapiHandlerOfDoubleArray }, { NWebValue::Type::INT64ARRAY, ConvertToNapiHandlerOfInt64Array } }; auto it = functionMap.find(type); if (it == functionMap.end()) { WVLOG_E("This type not support"); std::string msgStr = "This type not support"; napi_create_string_utf8(env, msgStr.c_str(), msgStr.length(), &dst); return true; } return it->second(env, src, dst); } bool IsFormatStringOfLength(const std::string &str) { std::regex pattern("^\\d+(px|vp|%)?$"); return std::regex_match(str, pattern); } bool IsNumberOfLength(const std::string &value) { if (value.empty()) { return false; } return std::all_of(value.begin(), value.end(), [](char i) { return isdigit(i); }); } bool NapiParseUtils::ParseJsLengthStringToInt(const std::string &input, PixelUnit &type, int32_t &value) { if (input.empty() || input.size() >= MAX_STRING_TO_INT32_LENGTH) { return false; } if (!IsFormatStringOfLength(input)) { return false; } if (IsNumberOfLength(input)) { try { value = std::stoi(input); } catch (std::out_of_range&) { WVLOG_E("input trans failed: out of range"); value = 0; } type = PixelUnit::VP; return true; } if (input.back() == '%') { std::string trans = input.substr(0, input.length() - 1); if (IsNumberOfLength(trans)) { try { value = std::stoi(trans); } catch (std::out_of_range&) { WVLOG_E("input trans failed: out of range"); value = 0; } type = PixelUnit::PERCENTAGE; return true; } return false; } if (input.length() < INTEGER_THREE) { return false; } std::string lastTwo = input.substr(input.length() - INTEGER_TWO); std::string trans = input.substr(0, input.length() - INTEGER_TWO); if (!IsNumberOfLength(trans)) { return false; } if (lastTwo == "px") { try { value = std::stoi(trans); } catch (std::out_of_range&) { WVLOG_E("input trans failed: out of range"); value = 0; } type = PixelUnit::PX; return true; } else if (lastTwo == "vp") { try { value = std::stoi(trans); } catch (std::out_of_range&) { WVLOG_E("input trans failed: out of range"); value = 0; } type = PixelUnit::VP; return true; } return false; } ErrCode NapiParseUtils::ConstructStringFlowbuf(napi_env env, napi_value argv, int& fd, size_t& scriptLength) { napi_valuetype valueType = napi_undefined; napi_typeof(env, argv, &valueType); if (valueType != napi_string) { WVLOG_E("Not a valid napi string"); return NWebError::PARAM_CHECK_ERROR; } napi_get_value_string_utf8(env, argv, nullptr, 0, &scriptLength); if (scriptLength + 1 > MAX_FLOWBUF_DATA_SIZE) { WVLOG_E("String length is too long"); return NWebError::PARAM_CHECK_ERROR; } // get ashmem auto flowbufferAdapter = OhosAdapterHelper::GetInstance().CreateFlowbufferAdapter(); if (!flowbufferAdapter) { WVLOG_E("Create flowbuffer adapter failed"); return NWebError::NEW_OOM; } auto ashmem = flowbufferAdapter->CreateAshmem(scriptLength + 1, PROT_READ | PROT_WRITE, fd); if (!ashmem) { return NWebError::NEW_OOM; } // write to ashmem size_t jsStringLength = 0; napi_get_value_string_utf8(env, argv, static_cast(ashmem), scriptLength + 1, &jsStringLength); if (jsStringLength != scriptLength) { close(fd); WVLOG_E("Write js string failed, the length values are different"); return NWebError::PARAM_CHECK_ERROR; } return NWebError::NO_ERROR; } ErrCode NapiParseUtils::ConstructArrayBufFlowbuf(napi_env env, napi_value argv, int& fd, size_t& scriptLength) { bool isArrayBuffer = false; if (napi_ok != napi_is_arraybuffer(env, argv, &isArrayBuffer) || !isArrayBuffer) { WVLOG_E("Not a valid napi ArrayBuffer"); return NWebError::PARAM_CHECK_ERROR; } char *arrBuf = nullptr; napi_get_arraybuffer_info(env, argv, (void**)&arrBuf, &scriptLength); if (!arrBuf) { WVLOG_E("Get arrayBuffer info failed"); return NWebError::PARAM_CHECK_ERROR; } if (scriptLength + 1 > MAX_FLOWBUF_DATA_SIZE) { WVLOG_E("Arraybuffer length is too long"); return NWebError::PARAM_CHECK_ERROR; } // get ashmem auto flowbufferAdapter = OhosAdapterHelper::GetInstance().CreateFlowbufferAdapter(); if (!flowbufferAdapter) { WVLOG_E("Create flowbuffer adapter failed"); return NWebError::NEW_OOM; } auto ashmem = flowbufferAdapter->CreateAshmem(scriptLength + 1, PROT_READ | PROT_WRITE, fd); if (!ashmem) { return NWebError::NEW_OOM; } // write to ashmem if (memcpy_s(ashmem, scriptLength + 1, arrBuf, scriptLength) != EOK) { WVLOG_E("ConstructArrayBufFlowbuf, memory copy failed"); return NWebError::NEW_OOM; } static_cast(ashmem)[scriptLength] = '\0'; return NWebError::NO_ERROR; } } // namespace NWeb } // namespace OHOS