* Copyright (c) 2025 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 "extra_config_napi.h"
#include "js_utils.h"
namespace OHOS {
namespace MiscServices {
napi_status JsExtraConfig::GetValue(napi_env env, napi_value in, ExtraConfig &out, uint32_t maxLen)
{
if (maxLen > DEFAULT_MAX_EXTRA_CONFIG_SIZE) {
maxLen = DEFAULT_MAX_EXTRA_CONFIG_SIZE;
}
napi_valuetype type = napi_undefined;
napi_status status = napi_typeof(env, in, &type);
CHECK_RETURN(type != napi_undefined, "param is undefined.", napi_generic_failure);
napi_value propType = nullptr;
status = napi_get_named_property(env, in, "customSettings", &propType);
CHECK_RETURN((status == napi_ok), "no property customSettings ", status);
return GetValue(env, propType, out.customSettings, maxLen);
}
napi_status JsExtraConfig::GetValue(napi_env env, napi_value in, CustomSettings &out, uint32_t maxLen)
{
napi_valuetype type = napi_undefined;
napi_status status = napi_typeof(env, in, &type);
CHECK_RETURN(type != napi_undefined, "param is undefined.", status);
napi_value keys = nullptr;
status = napi_get_property_names(env, in, &keys);
CHECK_RETURN(status == napi_ok, "get_property_names error.", status);
uint32_t arrLen = 0;
status = napi_get_array_length(env, keys, &arrLen);
CHECK_RETURN(status == napi_ok, "napi_get_array_length error.", status);
IMSA_HILOGD("length : %{public}u", arrLen);
uint32_t totalSize = 0;
for (size_t iter = 0; iter < arrLen; ++iter) {
napi_value key = nullptr;
status = napi_get_element(env, keys, iter, &key);
CHECK_RETURN(status == napi_ok, "napi_get_element error", status);
napi_value value = nullptr;
status = napi_get_property(env, in, key, &value);
CHECK_RETURN(status == napi_ok, "napi_get_property error", status);
std::string keyStr;
status = JsUtils::GetValue(env, key, keyStr);
CHECK_RETURN(status == napi_ok, "GetValue keyStr error", status);
uint32_t keySize = keyStr.size();
CustomValueType customSettingData;
uint32_t valueSize = 0;
status = GetValue(env, value, customSettingData, valueSize);
CHECK_RETURN(status == napi_ok, "GetValue customSettingData error", status);
if (totalSize > UINT32_MAX - keySize - valueSize) {
out.clear();
IMSA_HILOGE("integer overflow detected in size calculation");
return napi_generic_failure;
}
totalSize = totalSize + keySize + valueSize;
out.emplace(keyStr, customSettingData);
}
ExtraConfigInner configInner;
configInner.customSettings = out;
if (totalSize > maxLen || !configInner.IsMarshallingPass()) {
out.clear();
IMSA_HILOGE("input data exceed limit. totalSize: %{public}d, maxLen: %{public}d", totalSize, maxLen);
return napi_generic_failure;
}
return status;
}
napi_status JsExtraConfig::GetValue(napi_env env, napi_value in, CustomValueType &out, uint32_t &valueSize)
{
napi_valuetype valueType = napi_undefined;
napi_status status = napi_typeof(env, in, &valueType);
CHECK_RETURN(status == napi_ok, "napi_typeof error", napi_generic_failure);
if (valueType == napi_string) {
std::string customSettingStr;
status = JsUtils::GetValue(env, in, customSettingStr);
CHECK_RETURN(status == napi_ok, "GetValue napi_string error", napi_generic_failure);
valueSize = customSettingStr.size();
out.emplace<std::string>(customSettingStr);
} else if (valueType == napi_boolean) {
bool customSettingBool = false;
status = JsUtils::GetValue(env, in, customSettingBool);
CHECK_RETURN(status == napi_ok, "GetValue napi_boolean error", napi_generic_failure);
valueSize = sizeof(bool);
out.emplace<bool>(customSettingBool);
} else if (valueType == napi_number) {
int32_t customSettingInt = 0;
status = JsUtils::GetValue(env, in, customSettingInt);
CHECK_RETURN(status == napi_ok, "GetValue napi_number error", napi_generic_failure);
valueSize = sizeof(int32_t);
out.emplace<int32_t>(customSettingInt);
} else {
CHECK_RETURN(false, "value type must be string | boolean | number", napi_generic_failure);
}
return status;
}
napi_status JsExtraConfig::CreateExtraConfig(napi_env env, const ExtraConfig &in, napi_value &out)
{
napi_value jsObject = nullptr;
CHECK_RETURN(napi_create_object(env, &jsObject) == napi_ok, "create_object error", napi_generic_failure);
for (const auto &iter : in.customSettings) {
size_t idx = iter.second.index();
napi_value value = nullptr;
if (idx == static_cast<size_t>(CustomValueTypeValue::CUSTOM_VALUE_TYPE_STRING)) {
auto stringValue = std::get_if<std::string>(&iter.second);
CHECK_RETURN(stringValue != nullptr, "stringValue is nullptr", napi_generic_failure);
CHECK_RETURN(napi_create_string_utf8(env, (*stringValue).c_str(), (*stringValue).size(), &value)
== napi_ok, "create_string_utf8 error", napi_generic_failure);
} else if (idx == static_cast<size_t>(CustomValueTypeValue::CUSTOM_VALUE_TYPE_BOOL)) {
auto boolValue = std::get_if<bool>(&iter.second);
CHECK_RETURN(boolValue != nullptr, "boolValue is nullptr", napi_generic_failure);
CHECK_RETURN(napi_get_boolean(env, *boolValue, &value) == napi_ok, "get_boolean error",
napi_generic_failure);
} else if (idx == static_cast<size_t>(CustomValueTypeValue::CUSTOM_VALUE_TYPE_NUMBER)) {
auto numberValue = std::get_if<int32_t>(&iter.second);
CHECK_RETURN(numberValue != nullptr, "numberValue is nullptr", napi_generic_failure);
CHECK_RETURN(napi_create_int32(env, *numberValue, &value) == napi_ok, "create_int32 error",
napi_generic_failure);
}
CHECK_RETURN(napi_set_named_property(env, jsObject, iter.first.c_str(), value) == napi_ok,
"set_named_property error", napi_generic_failure);
}
std::string name = "customSettings";
CHECK_RETURN(napi_set_named_property(env, out, name.c_str(), jsObject) == napi_ok, "set_named_property error",
napi_generic_failure);
return napi_ok;
}
napi_status JsExtraConfig::GetExtraConfig(napi_env env, napi_value in, ExtraConfig &out, uint32_t maxLen)
{
if (maxLen > DEFAULT_MAX_EXTRA_CONFIG_SIZE) {
maxLen = DEFAULT_MAX_EXTRA_CONFIG_SIZE;
}
auto status = GetValue(env, in, out, maxLen);
CHECK_RETURN(status == napi_ok, "ExtraConfig convert failed", status);
return napi_ok;
}
}
}