1/* 2 * Copyright (c) 2022-2023 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 "js_utils.h" 17 18#include "js_util.h" 19 20namespace OHOS { 21namespace MiscServices { 22constexpr int32_t STR_MAX_LENGTH = 4096; 23constexpr size_t STR_TAIL_LENGTH = 1; 24constexpr size_t ARGC_MAX = 6; 25const std::map<int32_t, int32_t> JsUtils::ERROR_CODE_MAP = { 26 { ErrorCode::ERROR_CONTROLLER_INVOKING_FAILED, EXCEPTION_CONTROLLER }, 27 { ErrorCode::ERROR_STATUS_PERMISSION_DENIED, EXCEPTION_PERMISSION }, 28 { ErrorCode::ERROR_STATUS_SYSTEM_PERMISSION, EXCEPTION_SYSTEM_PERMISSION }, 29 { ErrorCode::ERROR_REMOTE_CLIENT_DIED, EXCEPTION_IMCLIENT }, 30 { ErrorCode::ERROR_CLIENT_NOT_FOUND, EXCEPTION_IMCLIENT }, 31 { ErrorCode::ERROR_CLIENT_NULL_POINTER, EXCEPTION_IMCLIENT }, 32 { ErrorCode::ERROR_CLIENT_NOT_FOCUSED, EXCEPTION_IMCLIENT }, 33 { ErrorCode::ERROR_CLIENT_NOT_EDITABLE, EXCEPTION_IMCLIENT }, 34 { ErrorCode::ERROR_CLIENT_NOT_BOUND, EXCEPTION_DETACHED }, 35 { ErrorCode::ERROR_CLIENT_ADD_FAILED, EXCEPTION_IMCLIENT }, 36 { ErrorCode::ERROR_NULL_POINTER, EXCEPTION_IMMS }, 37 { ErrorCode::ERROR_BAD_PARAMETERS, EXCEPTION_IMMS }, 38 { ErrorCode::ERROR_SERVICE_START_FAILED, EXCEPTION_IMMS }, 39 { ErrorCode::ERROR_IME_START_FAILED, EXCEPTION_IMMS }, 40 { ErrorCode::ERROR_KBD_SHOW_FAILED, EXCEPTION_IMMS }, 41 { ErrorCode::ERROR_KBD_HIDE_FAILED, EXCEPTION_IMMS }, 42 { ErrorCode::ERROR_IME_NOT_STARTED, EXCEPTION_IMMS }, 43 { ErrorCode::ERROR_EX_NULL_POINTER, EXCEPTION_IMMS }, 44 { ErrorCode::ERROR_PERSIST_CONFIG, EXCEPTION_CONFPERSIST }, 45 { ErrorCode::ERROR_PACKAGE_MANAGER, EXCEPTION_PACKAGEMANAGER }, 46 { ErrorCode::ERROR_EX_UNSUPPORTED_OPERATION, EXCEPTION_IMMS }, 47 { ErrorCode::ERROR_EX_SERVICE_SPECIFIC, EXCEPTION_IMMS }, 48 { ErrorCode::ERROR_EX_PARCELABLE, EXCEPTION_IMMS }, 49 { ErrorCode::ERROR_EX_ILLEGAL_ARGUMENT, EXCEPTION_IMMS }, 50 { ErrorCode::ERROR_EX_ILLEGAL_STATE, EXCEPTION_IMMS }, 51 { ErrorCode::ERROR_IME_START_INPUT_FAILED, EXCEPTION_IMMS }, 52 { ErrorCode::ERROR_NOT_IME, EXCEPTION_IME }, 53 { ErrorCode::ERROR_IME, EXCEPTION_IMENGINE }, 54 { ErrorCode::ERROR_PARAMETER_CHECK_FAILED, EXCEPTION_PARAMCHECK }, 55 { ErrorCode::ERROR_NOT_DEFAULT_IME, EXCEPTION_DEFAULTIME }, 56 { ErrorCode::ERROR_ENABLE_IME, EXCEPTION_IMMS }, 57 { ErrorCode::ERROR_NOT_CURRENT_IME, EXCEPTION_IMMS }, 58 { ErrorCode::ERROR_PANEL_NOT_FOUND, EXCEPTION_PANEL_NOT_FOUND }, 59 { ErrorCode::ERROR_WINDOW_MANAGER, EXCEPTION_WINDOW_MANAGER }, 60 { ErrorCode::ERROR_GET_TEXT_CONFIG, EXCEPTION_IMCLIENT }, 61 { ErrorCode::ERROR_INVALID_PRIVATE_COMMAND_SIZE, EXCEPTION_PARAMCHECK }, 62 { ErrorCode::ERROR_TEXT_LISTENER_ERROR, EXCEPTION_IMCLIENT }, 63 { ErrorCode::ERROR_TEXT_PREVIEW_NOT_SUPPORTED, EXCEPTION_TEXT_PREVIEW_NOT_SUPPORTED }, 64 { ErrorCode::ERROR_INVALID_RANGE, EXCEPTION_PARAMCHECK }, 65}; 66 67const std::map<int32_t, std::string> JsUtils::ERROR_CODE_CONVERT_MESSAGE_MAP = { 68 { EXCEPTION_PERMISSION, "the permissions check fails." }, 69 { EXCEPTION_SYSTEM_PERMISSION, "not system application." }, 70 { EXCEPTION_PARAMCHECK, "the parameters check fails." }, 71 { EXCEPTION_UNSUPPORTED, "call unsupported api." }, 72 { EXCEPTION_PACKAGEMANAGER, "package manager error." }, 73 { EXCEPTION_IMENGINE, "input method engine error." }, 74 { EXCEPTION_IMCLIENT, "input method client error." }, 75 { EXCEPTION_IME, "not an input method extension." }, 76 { EXCEPTION_CONFPERSIST, "configuration persisting error." }, 77 { EXCEPTION_CONTROLLER, "input method controller error." }, 78 { EXCEPTION_SETTINGS, "input method settings extension error." }, 79 { EXCEPTION_IMMS, "input method manager service error." }, 80 { EXCEPTION_DETACHED, "input method not attached." }, 81 { EXCEPTION_DEFAULTIME, "not default input method configured by system." }, 82 { EXCEPTION_TEXT_PREVIEW_NOT_SUPPORTED, "text preview is not supported." }, 83 { EXCEPTION_PANEL_NOT_FOUND, "soft keyboard panel doesn't exist." }, 84 { EXCEPTION_WINDOW_MANAGER, "window manager service error." }, 85}; 86 87const std::map<int32_t, std::string> JsUtils::PARAMETER_TYPE = { 88 { TYPE_UNDEFINED, "napi_undefine." }, 89 { TYPE_NULL, "napi_null." }, 90 { TYPE_BOOLEAN, "napi_boolean." }, 91 { TYPE_NUMBER, "napi_number." }, 92 { TYPE_STRING, "napi_string." }, 93 { TYPE_SYMBOL, "napi_symbol." }, 94 { TYPE_OBJECT, "napi_object." }, 95 { TYPE_FUNCTION, "napi_function." }, 96 { TYPE_EXTERNAL, "napi_external." }, 97 { TYPE_BIGINT, "napi_bigint." }, 98}; 99 100void JsUtils::ThrowException(napi_env env, int32_t err, const std::string &msg, TypeCode type) 101{ 102 std::string errMsg = ToMessage(err); 103 napi_value error; 104 napi_value code; 105 napi_value message; 106 if (type == TypeCode::TYPE_NONE) { 107 errMsg = errMsg + " " + msg; 108 IMSA_HILOGE("THROW_ERROR message: %{public}s!", errMsg.c_str()); 109 } else { 110 auto iter = PARAMETER_TYPE.find(type); 111 if (iter != PARAMETER_TYPE.end()) { 112 errMsg = errMsg + "The type of " + msg + " must be " + iter->second; 113 IMSA_HILOGE("THROW_ERROR message: %{public}s!", errMsg.c_str()); 114 } 115 } 116 NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, errMsg.c_str(), NAPI_AUTO_LENGTH, &message)); 117 NAPI_CALL_RETURN_VOID(env, napi_create_error(env, nullptr, message, &error)); 118 NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, err, &code)); 119 NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, error, "code", code)); 120 NAPI_CALL_RETURN_VOID(env, napi_throw(env, error)); 121} 122 123napi_value JsUtils::ToError(napi_env env, int32_t code, const std::string &msg) 124{ 125 IMSA_HILOGD("ToError start"); 126 napi_value errorObj; 127 NAPI_CALL(env, napi_create_object(env, &errorObj)); 128 napi_value errorCode = nullptr; 129 NAPI_CALL(env, napi_create_int32(env, Convert(code), &errorCode)); 130 napi_value errorMessage = nullptr; 131 std::string errMsg = ToMessage(Convert(code)) + " " + msg; 132 NAPI_CALL(env, napi_create_string_utf8(env, errMsg.c_str(), NAPI_AUTO_LENGTH, &errorMessage)); 133 NAPI_CALL(env, napi_set_named_property(env, errorObj, "code", errorCode)); 134 NAPI_CALL(env, napi_set_named_property(env, errorObj, "message", errorMessage)); 135 IMSA_HILOGD("ToError end"); 136 return errorObj; 137} 138 139int32_t JsUtils::Convert(int32_t code) 140{ 141 IMSA_HILOGD("Convert start."); 142 auto iter = ERROR_CODE_MAP.find(code); 143 if (iter != ERROR_CODE_MAP.end()) { 144 IMSA_HILOGD("ErrorCode: %{public}d", iter->second); 145 return iter->second; 146 } 147 IMSA_HILOGD("Convert end."); 148 return ERROR_CODE_QUERY_FAILED; 149} 150 151const std::string JsUtils::ToMessage(int32_t code) 152{ 153 IMSA_HILOGD("ToMessage start"); 154 auto iter = ERROR_CODE_CONVERT_MESSAGE_MAP.find(code); 155 if (iter != ERROR_CODE_CONVERT_MESSAGE_MAP.end()) { 156 IMSA_HILOGD("ErrorMessage: %{public}s", (iter->second).c_str()); 157 return iter->second; 158 } 159 return "error is out of definition."; 160} 161 162bool JsUtils::Equals(napi_env env, napi_value value, napi_ref copy, std::thread::id threadId) 163{ 164 if (copy == nullptr) { 165 return value == nullptr; 166 } 167 168 if (threadId != std::this_thread::get_id()) { 169 IMSA_HILOGD("napi_value can not be compared"); 170 return false; 171 } 172 173 napi_value copyValue = nullptr; 174 napi_get_reference_value(env, copy, ©Value); 175 176 bool isEquals = false; 177 napi_strict_equals(env, value, copyValue, &isEquals); 178 IMSA_HILOGD("value compare result: %{public}d", isEquals); 179 return isEquals; 180} 181 182void *JsUtils::GetNativeSelf(napi_env env, napi_callback_info info) 183{ 184 size_t argc = ARGC_MAX; 185 void *native = nullptr; 186 napi_value self = nullptr; 187 napi_value argv[ARGC_MAX] = { nullptr }; 188 napi_status status = napi_invalid_arg; 189 napi_get_cb_info(env, info, &argc, argv, &self, nullptr); 190 CHECK_RETURN((self != nullptr && argc <= ARGC_MAX), "napi_get_cb_info failed!", nullptr); 191 192 status = napi_unwrap(env, self, &native); 193 CHECK_RETURN((status == napi_ok && native != nullptr), "napi_unwrap failed!", nullptr); 194 return native; 195} 196 197napi_status JsUtils::GetValue(napi_env env, napi_value in, int32_t &out) 198{ 199 napi_valuetype type = napi_undefined; 200 napi_status status = napi_typeof(env, in, &type); 201 CHECK_RETURN((status == napi_ok) && (type == napi_number), "invalid type", napi_generic_failure); 202 return napi_get_value_int32(env, in, &out); 203} 204 205/* napi_value <-> uint32_t */ 206napi_status JsUtils::GetValue(napi_env env, napi_value in, uint32_t &out) 207{ 208 napi_valuetype type = napi_undefined; 209 napi_status status = napi_typeof(env, in, &type); 210 CHECK_RETURN((status == napi_ok) && (type == napi_number), "invalid type", napi_generic_failure); 211 return napi_get_value_uint32(env, in, &out); 212} 213 214napi_status JsUtils::GetValue(napi_env env, napi_value in, bool &out) 215{ 216 napi_valuetype type = napi_undefined; 217 napi_status status = napi_typeof(env, in, &type); 218 CHECK_RETURN((status == napi_ok) && (type == napi_boolean), "invalid type", napi_generic_failure); 219 return napi_get_value_bool(env, in, &out); 220} 221 222napi_status JsUtils::GetValue(napi_env env, napi_value in, double &out) 223{ 224 napi_valuetype type = napi_undefined; 225 napi_status status = napi_typeof(env, in, &type); 226 CHECK_RETURN((status == napi_ok) && (type == napi_number), "invalid double type", napi_generic_failure); 227 return napi_get_value_double(env, in, &out); 228} 229 230/* napi_value <-> std::string */ 231napi_status JsUtils::GetValue(napi_env env, napi_value in, std::string &out) 232{ 233 IMSA_HILOGD("JsUtils get string value in."); 234 napi_valuetype type = napi_undefined; 235 napi_status status = napi_typeof(env, in, &type); 236 CHECK_RETURN((status == napi_ok) && (type == napi_string), "invalid type", napi_generic_failure); 237 238 size_t maxLen = STR_MAX_LENGTH; 239 status = napi_get_value_string_utf8(env, in, NULL, 0, &maxLen); 240 if (maxLen <= 0) { 241 return status; 242 } 243 IMSA_HILOGD("napi_value -> std::string get length %{public}zu", maxLen); 244 char *buf = new (std::nothrow) char[maxLen + STR_TAIL_LENGTH]; 245 if (buf != nullptr) { 246 size_t len = 0; 247 status = napi_get_value_string_utf8(env, in, buf, maxLen + STR_TAIL_LENGTH, &len); 248 if (status == napi_ok) { 249 buf[len] = 0; 250 out = std::string(buf); 251 } 252 delete[] buf; 253 } else { 254 status = napi_generic_failure; 255 } 256 return status; 257} 258 259/* napi_value <-> std::unordered_map<string, string> */ 260napi_status JsUtils::GetValue(napi_env env, napi_value in, std::unordered_map<std::string, PrivateDataValue> &out) 261{ 262 napi_valuetype type = napi_undefined; 263 napi_status status = napi_typeof(env, in, &type); 264 PARAM_CHECK_RETURN(env, type != napi_undefined, "param is undefined.", TYPE_NONE, napi_generic_failure); 265 266 napi_value keys = nullptr; 267 napi_get_property_names(env, in, &keys); 268 uint32_t arrLen = 0; 269 status = napi_get_array_length(env, keys, &arrLen); 270 if (status != napi_ok) { 271 IMSA_HILOGE("napi_get_array_length error"); 272 return status; 273 } 274 // 5 means max private command count. 275 PARAM_CHECK_RETURN(env, arrLen <= 5 && arrLen > 0, "privateCommand must more than 0 and less than 5.", TYPE_NONE, 276 napi_generic_failure); 277 IMSA_HILOGD("length : %{public}u", arrLen); 278 for (size_t iter = 0; iter < arrLen; ++iter) { 279 napi_value key = nullptr; 280 status = napi_get_element(env, keys, iter, &key); 281 CHECK_RETURN(status == napi_ok, "napi_get_element error", status); 282 283 napi_value value = nullptr; 284 status = napi_get_property(env, in, key, &value); 285 CHECK_RETURN(status == napi_ok, "napi_get_property error", status); 286 287 std::string keyStr; 288 status = GetValue(env, key, keyStr); 289 CHECK_RETURN(status == napi_ok, "GetValue keyStr error", status); 290 291 PrivateDataValue privateCommand; 292 status = GetValue(env, value, privateCommand); 293 CHECK_RETURN(status == napi_ok, "GetValue privateCommand error", status); 294 out.emplace(keyStr, privateCommand); 295 } 296 return status; 297} 298 299napi_status JsUtils::GetValue(napi_env env, napi_value in, PrivateDataValue &out) 300{ 301 napi_valuetype valueType = napi_undefined; 302 napi_status status = napi_typeof(env, in, &valueType); 303 CHECK_RETURN(status == napi_ok, "napi_typeof error", napi_generic_failure); 304 if (valueType == napi_string) { 305 std::string privateDataStr; 306 status = GetValue(env, in, privateDataStr); 307 CHECK_RETURN(status == napi_ok, "GetValue napi_string error", napi_generic_failure); 308 out.emplace<std::string>(privateDataStr); 309 } else if (valueType == napi_boolean) { 310 bool privateDataBool = false; 311 status = GetValue(env, in, privateDataBool); 312 CHECK_RETURN(status == napi_ok, "GetValue napi_boolean error", napi_generic_failure); 313 out.emplace<bool>(privateDataBool); 314 } else if (valueType == napi_number) { 315 int32_t privateDataInt = 0; 316 status = GetValue(env, in, privateDataInt); 317 CHECK_RETURN(status == napi_ok, "GetValue napi_number error", napi_generic_failure); 318 out.emplace<int32_t>(privateDataInt); 319 } else { 320 PARAM_CHECK_RETURN(env, false, "value type must be string | boolean | number", TYPE_NONE, napi_generic_failure); 321 } 322 return status; 323} 324 325napi_status JsUtils::GetValue(napi_env env, napi_value in, const std::string &type, napi_value &out) 326{ 327 napi_valuetype valueType = napi_undefined; 328 napi_status status = napi_typeof(env, in, &valueType); 329 if ((status == napi_ok) && (valueType == napi_object)) { 330 status = napi_get_named_property(env, in, type.c_str(), &out); 331 return status; 332 } 333 return napi_generic_failure; 334} 335 336/* napi_value <-> PanelInfo */ 337napi_status JsUtils::GetValue(napi_env env, napi_value in, PanelInfo &out) 338{ 339 IMSA_HILOGD("napi_value -> PanelInfo "); 340 napi_value propType = nullptr; 341 napi_status status = napi_get_named_property(env, in, "type", &propType); 342 CHECK_RETURN((status == napi_ok), "no property type ", status); 343 int32_t panelType = 0; 344 status = GetValue(env, propType, panelType); 345 CHECK_RETURN((status == napi_ok), "no value of type ", status); 346 347 // PanelFlag is optional, defaults to FLG_FIXED when empty. 348 int32_t panelFlag = static_cast<int32_t>(PanelFlag::FLG_FIXED); 349 napi_value panelFlagObj = nullptr; 350 status = napi_get_named_property(env, in, "flag", &panelFlagObj); 351 if (status == napi_ok) { 352 JsUtils::GetValue(env, panelFlagObj, panelFlag); 353 } 354 355 out.panelType = PanelType(panelType); 356 out.panelFlag = PanelFlag(panelFlag); 357 return napi_ok; 358} 359 360napi_value JsUtils::GetValue(napi_env env, const std::vector<InputWindowInfo> &in) 361{ 362 napi_value array = nullptr; 363 uint32_t index = 0; 364 napi_create_array(env, &array); 365 if (array == nullptr) { 366 IMSA_HILOGE("create array failed"); 367 return array; 368 } 369 for (const auto &info : in) { 370 napi_value jsInfo = GetValue(env, info); 371 napi_set_element(env, array, index, jsInfo); 372 ++index; 373 } 374 return array; 375} 376 377napi_value JsUtils::GetValue(napi_env env, const InputWindowInfo &in) 378{ 379 napi_value info = nullptr; 380 napi_create_object(env, &info); 381 382 napi_value name = nullptr; 383 napi_create_string_utf8(env, in.name.c_str(), in.name.size(), &name); 384 napi_set_named_property(env, info, "name", name); 385 386 napi_value left = nullptr; 387 napi_create_int32(env, in.left, &left); 388 napi_set_named_property(env, info, "left", left); 389 390 napi_value top = nullptr; 391 napi_create_int32(env, in.top, &top); 392 napi_set_named_property(env, info, "top", top); 393 394 napi_value width = nullptr; 395 napi_create_uint32(env, in.width, &width); 396 napi_set_named_property(env, info, "width", width); 397 398 napi_value height = nullptr; 399 napi_create_uint32(env, in.height, &height); 400 napi_set_named_property(env, info, "height", height); 401 402 return info; 403} 404 405napi_status JsUtils::GetValue(napi_env env, const std::string &in, napi_value &out) 406{ 407 return napi_create_string_utf8(env, in.c_str(), in.size(), &out); 408} 409 410napi_value JsUtils::GetJsPrivateCommand(napi_env env, const std::unordered_map<std::string, PrivateDataValue> &in) 411{ 412 napi_value jsPrivateCommand = nullptr; 413 NAPI_CALL(env, napi_create_object(env, &jsPrivateCommand)); 414 for (const auto &iter : in) { 415 size_t idx = iter.second.index(); 416 napi_value value = nullptr; 417 if (idx == static_cast<size_t>(PrivateDataValueType::VALUE_TYPE_STRING)) { 418 auto stringValue = std::get_if<std::string>(&iter.second); 419 if (stringValue != nullptr) { 420 NAPI_CALL(env, napi_create_string_utf8(env, (*stringValue).c_str(), (*stringValue).size(), &value)); 421 } 422 } else if (idx == static_cast<size_t>(PrivateDataValueType::VALUE_TYPE_BOOL)) { 423 auto boolValue = std::get_if<bool>(&iter.second); 424 if (boolValue != nullptr) { 425 NAPI_CALL(env, napi_get_boolean(env, *boolValue, &value)); 426 } 427 } else if (idx == static_cast<size_t>(PrivateDataValueType::VALUE_TYPE_NUMBER)) { 428 auto numberValue = std::get_if<int32_t>(&iter.second); 429 if (numberValue != nullptr) { 430 NAPI_CALL(env, napi_create_int32(env, *numberValue, &value)); 431 } 432 } 433 NAPI_CALL(env, napi_set_named_property(env, jsPrivateCommand, iter.first.c_str(), value)); 434 } 435 return jsPrivateCommand; 436} 437} // namespace MiscServices 438} // namespace OHOS