* Copyright (c) 2021 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 "js_common_utils.h"
#include <cstdint>
#include <tuple>
#include <utility>
#include "hilog/log_c.h"
#include "js_native_api.h"
#include "js_native_api_types.h"
#include "log_print.h"
namespace OHOS {
namespace PreferencesJsKit {
using namespace OHOS::NativePreferences;
int32_t JSUtils::Convert2NativeValue(napi_env env, napi_value jsValue, std::string &output)
{
size_t bufferSize = 0;
napi_status status = napi_get_value_string_utf8(env, jsValue, nullptr, 0, &bufferSize);
if (status != napi_ok) {
LOG_DEBUG("get std::string failed, status = %{public}d", status);
return NAPI_TYPE_ERROR;
}
if (bufferSize > MAX_VALUE_LENGTH) {
LOG_ERROR("string must be less than the limit length.");
return EXCEED_MAX_LENGTH;
}
char *buffer = (char *)malloc(bufferSize + 1);
if (buffer == nullptr) {
LOG_ERROR("malloc failed, buffer is nullptr.");
return ERR;
}
status = napi_get_value_string_utf8(env, jsValue, buffer, bufferSize + 1, &bufferSize);
if (status != napi_ok) {
free(buffer);
LOG_DEBUG("JSUtils::Convert2NativeValue get jsVal failed, status = %{public}d", status);
return status;
}
output = buffer;
free(buffer);
return napi_ok;
}
int32_t JSUtils::Convert2NativeValue(napi_env env, napi_value jsValue, bool &output)
{
bool bValue = false;
napi_status status = napi_get_value_bool(env, jsValue, &bValue);
if (status != napi_ok) {
LOG_DEBUG("get bool failed, status = %{public}d", status);
return NAPI_TYPE_ERROR;
}
output = bValue;
return napi_ok;
}
int32_t JSUtils::Convert2NativeValue(napi_env env, napi_value jsValue, double &output)
{
double number = 0.0;
napi_status status = napi_get_value_double(env, jsValue, &number);
if (status != napi_ok) {
LOG_DEBUG("get double failed, status = %{public}d", status);
return NAPI_TYPE_ERROR;
}
output = number;
return napi_ok;
}
int32_t JSUtils::Convert2NativeValue(napi_env env, napi_value jsValue, float &output)
{
LOG_DEBUG("Convert2NativeValue js just support double data not support float");
return NAPI_TYPE_ERROR;
}
int32_t JSUtils::Convert2NativeValue(napi_env env, napi_value jsValue, int32_t &output)
{
LOG_DEBUG("Convert2NativeValue js just support double data not support int32_t");
return NAPI_TYPE_ERROR;
}
int32_t JSUtils::Convert2NativeValue(napi_env env, napi_value jsValue, int64_t &output)
{
LOG_DEBUG("Convert2NativeValue js just support double data not support int64_t");
return NAPI_TYPE_ERROR;
}
int32_t JSUtils::Convert2NativeValue(napi_env env, napi_value jsValue, std::vector<uint8_t> &output)
{
bool isTypedarray = false;
napi_status result = napi_is_typedarray(env, jsValue, &isTypedarray);
if (result != napi_ok || !isTypedarray) {
LOG_DEBUG("napi_is_typedarray fail. result %{public}d isTypedarray %{public}d", result, isTypedarray);
return NAPI_TYPE_ERROR;
}
napi_typedarray_type type = napi_uint8_array;
size_t length = 0;
void *data = nullptr;
result = napi_get_typedarray_info(env, jsValue, &type, &length, &data, nullptr, nullptr);
if (result != napi_ok) {
LOG_ERROR("napi_get_typedarray_info fail");
return result;
}
if (type != napi_uint8_array) {
LOG_ERROR("value is not napi_uint8_array");
return NAPI_TYPE_ERROR;
}
if (length > MAX_VALUE_LENGTH) {
LOG_ERROR("unit8Array must be less than the limit length.");
return EXCEED_MAX_LENGTH;
}
output.clear();
if (length > 0) {
output.resize(length);
output.assign(static_cast<uint8_t*>(data), static_cast<uint8_t*>(data) + length);
}
return napi_ok;
}
int32_t JSUtils::Convert2NativeValue(napi_env env, napi_value jsValue, Object &output)
{
if (GetValueType(env, jsValue) != napi_object) {
LOG_DEBUG("Not of object type.");
return NAPI_TYPE_ERROR;
}
auto [status, jsonStr] = JsonStringify(env, jsValue);
if (status != napi_ok) {
LOG_ERROR("json stringify failed.");
return status;
}
return Convert2NativeValue(env, jsonStr, output.valueStr);
}
int32_t JSUtils::Convert2NativeValue(napi_env env, napi_value jsValue, BigInt &output)
{
if (GetValueType(env, jsValue) != napi_bigint) {
LOG_DEBUG("Not of bigint type.");
return NAPI_TYPE_ERROR;
}
size_t wordCount = 0;
napi_status status = napi_get_value_bigint_words(env, jsValue, nullptr, &wordCount, nullptr);
if (status != napi_ok || wordCount == 0) {
LOG_ERROR("get wordCount failed %{public}d wordCount %{public}zu.", status, wordCount);
return status;
}
output.words_.resize(wordCount);
status = napi_get_value_bigint_words(env, jsValue, &output.sign_, &wordCount, output.words_.data());
if (status != napi_ok) {
LOG_ERROR("napi_get_value_bigint_words failed %{public}d wordCount %{public}zu.", status, wordCount);
return status;
}
return napi_ok;
}
int32_t JSUtils::Convert2NativeValue(napi_env env, napi_value jsValue, std::monostate &value)
{
return NAPI_TYPE_ERROR;
}
bool JSUtils::Equals(napi_env env, napi_value value, napi_ref copy)
{
if (copy == nullptr || env == nullptr) {
return (value == nullptr);
}
napi_value copyValue = nullptr;
napi_get_reference_value(env, copy, ©Value);
bool isEquals = false;
napi_strict_equals(env, value, copyValue, &isEquals);
return isEquals;
}
napi_value JSUtils::Convert2JSValue(napi_env env, int32_t value)
{
napi_value jsValue;
if (napi_create_int32(env, value, &jsValue) != napi_ok) {
LOG_DEBUG("Convert int32_t failed");
return nullptr;
}
return jsValue;
}
napi_value JSUtils::Convert2JSValue(napi_env env, uint32_t value)
{
napi_value jsValue;
if (napi_create_uint32(env, value, &jsValue) != napi_ok) {
LOG_DEBUG("Convert uint32_t failed");
return nullptr;
}
return jsValue;
}
napi_value JSUtils::Convert2JSValue(napi_env env, int64_t value)
{
napi_value jsValue;
if (napi_create_int64(env, value, &jsValue) != napi_ok) {
LOG_DEBUG("Convert int64_t failed");
return nullptr;
}
return jsValue;
}
napi_value JSUtils::Convert2JSValue(napi_env env, bool value)
{
napi_value jsValue;
if (napi_get_boolean(env, value, &jsValue) != napi_ok) {
LOG_DEBUG("Convert bool failed");
return nullptr;
}
return jsValue;
}
napi_value JSUtils::Convert2JSValue(napi_env env, double value)
{
napi_value jsValue;
if (napi_create_double(env, value, &jsValue) != napi_ok) {
LOG_DEBUG("Convert double failed");
return nullptr;
}
return jsValue;
}
napi_value JSUtils::Convert2JSValue(napi_env env, float value)
{
napi_value jsValue;
if (napi_create_double(env, value, &jsValue) != napi_ok) {
LOG_DEBUG("Convert float failed");
return nullptr;
}
return jsValue;
}
napi_value JSUtils::Convert2JSValue(napi_env env, const std::vector<uint8_t> &value)
{
size_t size = value.size();
void *data = nullptr;
napi_value buffer = nullptr;
napi_status ret = napi_create_arraybuffer(env, size, &data, &buffer);
if (ret != napi_ok) {
LOG_ERROR("napi_create_arraybuffer failed %{public}d", ret);
return nullptr;
}
if (size != 0) {
std::copy(value.begin(), value.end(), static_cast<uint8_t*>(data));
}
napi_value napiValue = nullptr;
ret = napi_create_typedarray(env, napi_uint8_array, size, buffer, 0, &napiValue);
if (ret != napi_ok) {
LOG_ERROR("napi_create_typedarray failed %{public}d", ret);
return nullptr;
}
return napiValue;
}
napi_value JSUtils::Convert2JSValue(napi_env env, const Object &value)
{
napi_value jsValue = JsonParse(env, value.valueStr);
if (jsValue == nullptr) {
LOG_ERROR("Convert object failed");
}
return jsValue;
}
napi_value JSUtils::Convert2JSValue(napi_env env, const std::string &value)
{
napi_value jsValue = nullptr;
if (napi_create_string_utf8(env, value.c_str(), value.size(), &jsValue) != napi_ok) {
LOG_DEBUG("Convert std::string failed");
return nullptr;
}
return jsValue;
}
napi_value JSUtils::Convert2JSValue(napi_env env, const BigInt &value)
{
napi_value bigint = nullptr;
napi_status status = napi_create_bigint_words(env, value.sign_, value.words_.size(), value.words_.data(), &bigint);
if (status != napi_ok || bigint == nullptr) {
LOG_ERROR("napi_create_bigint_words failed %{public}d", status);
return nullptr;
}
return bigint;
}
napi_value JSUtils::Convert2JSValue(napi_env env, const std::monostate &value)
{
napi_value result = nullptr;
napi_get_null(env, &result);
return result;
}
napi_valuetype JSUtils::GetValueType(napi_env env, napi_value value)
{
napi_valuetype valueType = napi_undefined;
napi_typeof(env, value, &valueType);
return valueType;
}
std::tuple<napi_status, napi_value> JSUtils::JsonStringify(napi_env env, napi_value value)
{
napi_value global = nullptr;
napi_status status = napi_get_global(env, &global);
PRE_CHECK_RETURN_CORE(status == napi_ok, PRE_REVT_NOTHING, std::make_tuple(status, nullptr));
napi_value json = nullptr;
status = napi_get_named_property(env, global, GLOBAL_JSON, &json);
PRE_CHECK_RETURN_CORE(status == napi_ok, PRE_REVT_NOTHING, std::make_tuple(status, nullptr));
napi_value stringify = nullptr;
status = napi_get_named_property(env, json, GLOBAL_STRINGIFY, &stringify);
PRE_CHECK_RETURN_CORE(status == napi_ok, PRE_REVT_NOTHING, std::make_tuple(status, nullptr));
napi_value res = nullptr;
napi_value argv[1] = {value};
status = napi_call_function(env, json, stringify, 1, argv, &res);
PRE_CHECK_RETURN_CORE(status == napi_ok, PRE_REVT_NOTHING, std::make_tuple(status, nullptr));
return std::make_tuple(napi_ok, res);
}
napi_value JSUtils::JsonParse(napi_env env, const std::string &inStr, bool sendable)
{
if (inStr.empty()) {
LOG_ERROR("JsonParse failed, inStr is empty");
return nullptr;
}
napi_value jsValue = Convert2JSValue(env, inStr);
napi_value global = nullptr;
PRE_CHECK_RETURN_CORE(napi_get_global(env, &global) == napi_ok, PRE_REVT_NOTHING, nullptr);
napi_value json = nullptr;
PRE_CHECK_RETURN_CORE(
napi_get_named_property(env, global, GLOBAL_JSON, &json) == napi_ok, PRE_REVT_NOTHING, nullptr);
napi_value parse = nullptr;
PRE_CHECK_RETURN_CORE(
napi_get_named_property(env, json, sendable ? GLOBAL_PARSE_SENDABLE : GLOBAL_PARSE, &parse) == napi_ok,
PRE_REVT_NOTHING, nullptr);
if (GetValueType(env, parse) != napi_function) {
LOG_ERROR("Get parse func failed");
return nullptr;
}
napi_value res = nullptr;
napi_value argv[1] = { jsValue };
PRE_CHECK_RETURN_CORE(napi_call_function(env, json, parse, 1, argv, &res) == napi_ok, PRE_REVT_NOTHING, nullptr);
return res;
}
}
}