1 /* 2 * Copyright (C) 2021-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 #include "napi_common_want.h" 16 #include "paste_data_record.h" 17 #include "pasteboard_common.h" 18 19 #include "pasteboard_hilog.h" 20 #include "pasteboard_js_err.h" 21 22 namespace OHOS { 23 namespace MiscServicesNapi { 24 using namespace OHOS::MiscServices; 25 const size_t ARGC_TYPE_SET2 = 2; 26 constexpr size_t STR_TAIL_LENGTH = 1; 27 constexpr int32_t MIMETYPE_MAX_SIZE = 1024; 28 GetCallbackErrorValue(napi_env env,int32_t errorCode)29 napi_value GetCallbackErrorValue(napi_env env, int32_t errorCode) 30 { 31 napi_value result = nullptr; 32 napi_value eCode = nullptr; 33 NAPI_CALL(env, napi_create_int32(env, errorCode, &eCode)); 34 NAPI_CALL(env, napi_create_object(env, &result)); 35 NAPI_CALL(env, napi_set_named_property(env, result, "code", eCode)); 36 return result; 37 } 38 SetCallback(const napi_env & env,const napi_ref & callbackIn,const napi_value * results)39 void SetCallback(const napi_env &env, const napi_ref &callbackIn, const napi_value *results) 40 { 41 if (results == nullptr) { 42 return; 43 } 44 napi_value callback = nullptr; 45 napi_value resultout = nullptr; 46 napi_get_reference_value(env, callbackIn, &callback); 47 napi_call_function(env, nullptr, callback, ARGC_TYPE_SET2, results, &resultout); 48 } 49 NapiGetNull(napi_env env)50 napi_value NapiGetNull(napi_env env) 51 { 52 napi_value result = nullptr; 53 napi_get_null(env, &result); 54 return result; 55 } 56 CreateNapiNumber(napi_env env,int32_t num)57 napi_value CreateNapiNumber(napi_env env, int32_t num) 58 { 59 napi_value value = nullptr; 60 napi_create_int32(env, num, &value); 61 return value; 62 } 63 CreateNapiString(napi_env env,std::string str)64 napi_value CreateNapiString(napi_env env, std::string str) 65 { 66 napi_value value = nullptr; 67 napi_create_string_utf8(env, str.c_str(), NAPI_AUTO_LENGTH, &value); 68 return value; 69 } 70 71 /* napi_value <-> std::string */ GetValue(napi_env env,napi_value in,std::string & out)72 bool GetValue(napi_env env, napi_value in, std::string &out) 73 { 74 napi_valuetype type = napi_undefined; 75 NAPI_CALL_BASE(env, napi_typeof(env, in, &type), false); 76 NAPI_ASSERT_BASE(env, type == napi_string, "Wrong argument type. String expected.", false); 77 78 size_t len = 0; 79 NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, in, nullptr, 0, &len), false); 80 if (len < 0) { 81 return false; 82 } 83 84 size_t length = 0; 85 out.resize(len + STR_TAIL_LENGTH, 0); 86 NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, in, out.data(), len + STR_TAIL_LENGTH, &length), false); 87 out.resize(len); 88 89 return true; 90 } 91 92 /* napi_value <-> std::set<Pattern> */ GetValue(napi_env env,napi_value in,std::set<MiscServices::Pattern> & out)93 bool GetValue(napi_env env, napi_value in, std::set<MiscServices::Pattern> &out) 94 { 95 bool isArray = false; 96 NAPI_CALL_BASE(env, napi_is_array(env, in, &isArray), false); 97 if (!isArray) { 98 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Wrong argument type. pattern/uint32 array expected."); 99 return false; 100 } 101 102 uint32_t len = 0; 103 napi_status status = napi_get_array_length(env, in, &len); 104 if (status != napi_ok || len == 0) { 105 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "napi_get_array_length status = %{public}d, len = %{public}d", 106 status, len); 107 return false; 108 } 109 110 for (uint32_t i = 0; i < len; i++) { 111 napi_value element; 112 napi_status status = napi_get_element(env, in, i, &element); 113 if (status != napi_ok) { 114 PASTEBOARD_HILOGE( 115 PASTEBOARD_MODULE_JS_NAPI, "napi_get_element%{public}d err status = %{public}d", i, status); 116 return false; 117 } 118 uint32_t pattern; 119 status = napi_get_value_uint32(env, element, &pattern); 120 if (status != napi_ok) { 121 PASTEBOARD_HILOGE( 122 PASTEBOARD_MODULE_JS_NAPI, "napi_get_value_uint32 err status = %{public}d", status); 123 return false; 124 } 125 if (pattern >= static_cast<uint32_t>(Pattern::PatternCount)) { 126 PASTEBOARD_HILOGE( 127 PASTEBOARD_MODULE_JS_NAPI, "Unsurportted pattern value: %{public}d", pattern); 128 return false; 129 } 130 out.insert(static_cast<Pattern>(pattern)); 131 } 132 return true; 133 } 134 135 /* napi_value <-> std::set<Pattern> */ SetValue(napi_env env,std::set<Pattern> & in,napi_value & result)136 napi_status SetValue(napi_env env, std::set<Pattern> &in, napi_value &result) 137 { 138 napi_status status = napi_create_array_with_length(env, in.size(), &result); 139 if (status != napi_ok) { 140 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "napi_create_array_with_length error status = %{public}d", status); 141 return status; 142 } 143 int i = 0; 144 for (auto &pattern : in) { 145 napi_value element; 146 status = napi_create_uint32(env, static_cast<uint32_t>(pattern), &element); 147 if (status != napi_ok) { 148 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "napi_create_uint32 error status = %{public}d", status); 149 return status; 150 } 151 status = napi_set_element(env, result, i, element); 152 if (status != napi_ok) { 153 PASTEBOARD_HILOGE( 154 PASTEBOARD_MODULE_JS_NAPI, "napi_set_element %{public}d err status = %{public}d", i, status); 155 return status; 156 } 157 ++i; 158 } 159 return status; 160 } 161 SetValue(napi_env env,const std::vector<std::string> & in,napi_value & out)162 napi_status SetValue(napi_env env, const std::vector<std::string> &in, napi_value &out) 163 { 164 PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "napi_value <- std::vector<std::string>"); 165 napi_status status = napi_create_array_with_length(env, in.size(), &out); 166 if (status != napi_ok) { 167 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "create array failed, status=%{public}d", status); 168 return status; 169 } 170 int index = 0; 171 for (auto &item : in) { 172 napi_value element = nullptr; 173 status = napi_create_string_utf8(env, item.c_str(), item.size(), &element); 174 if (status != napi_ok) { 175 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "napi_create_string_utf8 error status = %{public}d", status); 176 return status; 177 } 178 status = napi_set_element(env, out, index++, element); 179 if (status != napi_ok) { 180 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "napi_set_element failed, status=%{public}d", status); 181 return status; 182 } 183 } 184 return status; 185 } 186 CheckArgsType(napi_env env,napi_value in,napi_valuetype expectedType,const char * message)187 bool CheckArgsType(napi_env env, napi_value in, napi_valuetype expectedType, const char *message) 188 { 189 napi_valuetype type = napi_undefined; 190 NAPI_CALL_BASE(env, napi_typeof(env, in, &type), false); 191 int32_t errCode = static_cast<int32_t>(JSErrorCode::INVALID_PARAMETERS); 192 if (type != expectedType) { 193 napi_throw_error(env, std::to_string(errCode).c_str(), message); 194 return false; 195 } 196 return true; 197 } 198 CheckExpression(napi_env env,bool flag,MiscServices::JSErrorCode errCode,const char * message)199 bool CheckExpression(napi_env env, bool flag, MiscServices::JSErrorCode errCode, const char *message) 200 { 201 if (!flag) { 202 NAPI_CALL_BASE( 203 env, napi_throw_error(env, std::to_string(static_cast<int32_t>(errCode)).c_str(), message), false); 204 return false; 205 } 206 return true; 207 } 208 209 // Check Parameters of CreateData, CreateRecord and AddRecord CheckArgs(napi_env env,napi_value * argv,size_t argc,std::string & mimeType)210 bool CheckArgs(napi_env env, napi_value *argv, size_t argc, std::string &mimeType) 211 { 212 // 2: CreateRecord, CreateRecord and AddRecord has 2 args. 213 if (!CheckExpression(env, argc >= ARGC_TYPE_SET2, JSErrorCode::INVALID_PARAMETERS, 214 "Parameter error. The number of arguments cannot be less than two.")) { 215 return false; 216 } 217 218 bool ret = CheckArgsMimeType(env, argv[0], mimeType); 219 if (!ret) { 220 return false; 221 } 222 223 if (mimeType == MIMETYPE_TEXT_URI || mimeType == MIMETYPE_TEXT_PLAIN || mimeType == MIMETYPE_TEXT_HTML) { 224 if (!CheckArgsType(env, argv[1], napi_string, "Parameter error. The type of mimeType must be string.")) { 225 return false; 226 } 227 } else if (mimeType == MIMETYPE_PIXELMAP) { 228 if (!CheckExpression(env, Media::PixelMapNapi::GetPixelMap(env, argv[1]) != nullptr, 229 JSErrorCode::INVALID_PARAMETERS, "Parameter error. Actual mimeType is not mimetype_pixelmap.")) { 230 return false; 231 } 232 } else if (mimeType == MIMETYPE_TEXT_WANT) { 233 AAFwk::Want want; 234 ret = OHOS::AppExecFwk::UnwrapWant(env, argv[1], want); 235 if (!CheckExpression(env, ret, JSErrorCode::INVALID_PARAMETERS, 236 "Parameter error. Actual mimeType is not mimetype_text_want.")) { 237 return false; 238 } 239 } else { 240 bool isArrayBuffer = false; 241 NAPI_CALL_BASE(env, napi_is_arraybuffer(env, argv[1], &isArrayBuffer), false); 242 if (!CheckExpression(env, isArrayBuffer, JSErrorCode::INVALID_PARAMETERS, 243 "Parameter error. The mimeType is not an arraybuffer.")) { 244 return false; 245 } 246 } 247 return true; 248 } 249 CheckArgsMimeType(napi_env env,napi_value in,std::string & mimeType)250 bool CheckArgsMimeType(napi_env env, napi_value in, std::string &mimeType) 251 { 252 bool ret = CheckArgsType(env, in, napi_string, "Parameter error. The type of mimeType must be string."); 253 if (!ret) { 254 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Wrong argument type. String expected."); 255 return false; 256 } 257 ret = GetValue(env, in, mimeType); 258 if (!ret) { 259 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "GetValue failed"); 260 return false; 261 } 262 if (!CheckExpression( 263 env, mimeType != "", JSErrorCode::INVALID_PARAMETERS, "Parameter error. mimeType cannot be empty.") || 264 !CheckExpression(env, mimeType.size() <= MIMETYPE_MAX_SIZE, JSErrorCode::INVALID_PARAMETERS, 265 "Parameter error. The length of mimeType cannot be greater than 1024 bytes.")) { 266 return false; 267 } 268 return true; 269 } 270 CheckArgsArray(napi_env env,napi_value in,std::vector<std::string> & mimeTypes)271 bool CheckArgsArray(napi_env env, napi_value in, std::vector<std::string> &mimeTypes) 272 { 273 napi_valuetype type = napi_undefined; 274 NAPI_CALL_BASE(env, napi_typeof(env, in, &type), false); 275 int32_t errCode = static_cast<int32_t>(JSErrorCode::INVALID_PARAMETERS); 276 if (type != napi_object) { 277 napi_throw_error(env, std::to_string(errCode).c_str(), "Wrong argument type. Object expected."); 278 return false; 279 } 280 281 bool isArray = false; 282 NAPI_CALL_BASE(env, napi_is_array(env, in, &isArray), false); 283 if (!isArray) { 284 return false; 285 } 286 287 uint32_t length = 0; 288 NAPI_CALL_BASE(env, napi_get_array_length(env, in, &length), false); 289 napi_value element; 290 for (uint32_t i = 0; i < length; i++) { 291 NAPI_CALL_BASE(env, napi_get_element(env, in, i, &element), false); 292 std::string mimeType; 293 if (!GetValue(env, element, mimeType)) { 294 return false; 295 } 296 mimeTypes.emplace_back(mimeType); 297 } 298 299 return true; 300 } 301 CheckArgsFunc(napi_env env,napi_value in,napi_ref & provider)302 bool CheckArgsFunc(napi_env env, napi_value in, napi_ref &provider) 303 { 304 napi_valuetype type = napi_undefined; 305 NAPI_CALL_BASE(env, napi_typeof(env, in, &type), false); 306 int32_t errCode = static_cast<int32_t>(JSErrorCode::INVALID_PARAMETERS); 307 if (type != napi_function) { 308 napi_throw_error(env, std::to_string(errCode).c_str(), "Wrong argument type. function expected."); 309 return false; 310 } 311 312 NAPI_CALL_BASE(env, napi_create_reference(env, in, 1, &provider), false); 313 314 return true; 315 } 316 CheckArgsVector(napi_env env,napi_value in,std::shared_ptr<std::vector<std::pair<std::string,std::shared_ptr<EntryValue>>>> result)317 bool CheckArgsVector(napi_env env, napi_value in, 318 std::shared_ptr<std::vector<std::pair<std::string, std::shared_ptr<EntryValue>>>> result) 319 { 320 napi_valuetype valueType = napi_undefined; 321 NAPI_CALL_BASE(env, napi_typeof(env, in, &valueType), false); 322 if (!CheckExpression(env, valueType == napi_object, JSErrorCode::INVALID_PARAMETERS, 323 "Parameter error. When there is only one parameter, it must be a Record.")) { 324 return false; 325 } 326 327 napi_value typeValueMap = nullptr; 328 NAPI_CALL_BASE(env, napi_get_property_names(env, in, &typeValueMap), false); 329 uint32_t length = 0; 330 NAPI_CALL_BASE(env, napi_get_array_length(env, typeValueMap, &length), false); 331 332 PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "length = %{public}u", length); 333 for (uint32_t i = 0; i < length; i++) { 334 napi_value mimeTypeNapi = nullptr; 335 NAPI_CALL_BASE(env, napi_get_element(env, typeValueMap, i, &mimeTypeNapi), false); 336 std::string mimeType; 337 bool ret = CheckArgsMimeType(env, mimeTypeNapi, mimeType); 338 if (!ret) { 339 return false; 340 } 341 napi_value value = nullptr; 342 std::shared_ptr<EntryValue> entryValue = std::make_shared<EntryValue>(); 343 NAPI_CALL_BASE(env, napi_get_property(env, in, mimeTypeNapi, &value), false); 344 if (!GetNativeValue(env, mimeType, value, *entryValue)) { 345 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "GetNativeValue failed"); 346 return false; 347 } 348 result->emplace_back(std::make_pair(mimeType, entryValue)); 349 } 350 return true; 351 } 352 ConvertEntryValue(napi_env env,napi_value * result,std::string & mimeType,std::shared_ptr<PasteDataEntry> value)353 napi_status ConvertEntryValue(napi_env env, napi_value *result, std::string &mimeType, 354 std::shared_ptr<PasteDataEntry> value) 355 { 356 if (value == nullptr) { 357 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "failed to find dataEntry"); 358 return napi_generic_failure; 359 } 360 if (mimeType == MIMETYPE_TEXT_URI) { 361 std::shared_ptr<Uri> uri = value->ConvertToUri(); 362 if (uri == nullptr) { 363 return napi_generic_failure; 364 } 365 std::string str = uri->ToString(); 366 return napi_create_string_utf8(env, str.c_str(), str.size(), result); 367 } else if (mimeType == MIMETYPE_TEXT_PLAIN) { 368 std::shared_ptr<std::string> str = value->ConvertToPlianText(); 369 if (str == nullptr) { 370 return napi_generic_failure; 371 } 372 return napi_create_string_utf8(env, str->c_str(), str->size(), result); 373 } else if (mimeType == MIMETYPE_TEXT_HTML) { 374 std::shared_ptr<std::string> str = value->ConvertToHtml(); 375 if (str == nullptr) { 376 return napi_generic_failure; 377 } 378 return napi_create_string_utf8(env, str->c_str(), str->size(), result); 379 } else if (mimeType == MIMETYPE_PIXELMAP) { 380 std::shared_ptr<Media::PixelMap> pixelMap = value->ConvertToPixelMap(); 381 if (!CheckExpression(env, pixelMap != nullptr, 382 JSErrorCode::INVALID_PARAMETERS, "Parameter error. pixelMap get failed")) { 383 return napi_generic_failure; 384 } 385 *result = Media::PixelMapNapi::CreatePixelMap(env, pixelMap); 386 return napi_ok; 387 } else if (mimeType == MIMETYPE_TEXT_WANT) { 388 std::shared_ptr<AAFwk::Want> want = value->ConvertToWant(); 389 if (!CheckExpression(env, want != nullptr, 390 JSErrorCode::INVALID_PARAMETERS, "Parameter error. want get failed")) { 391 return napi_generic_failure; 392 } 393 *result = AppExecFwk::WrapWant(env, *want); 394 return napi_ok; 395 } else { 396 std::shared_ptr<MineCustomData> customData = value->ConvertToCustomData(); 397 if (customData == nullptr) { 398 return napi_generic_failure; 399 } 400 auto itemData = customData->GetItemData(); 401 auto item = itemData.find(mimeType); 402 if (item == itemData.end()) { 403 return napi_generic_failure; 404 } 405 std::vector<uint8_t> dataArray = item->second; 406 void *data = nullptr; 407 size_t len = dataArray.size(); 408 NAPI_CALL_BASE(env, napi_create_arraybuffer(env, len, &data, result), napi_generic_failure); 409 if (memcpy_s(data, len, reinterpret_cast<const void *>(dataArray.data()), len) != 0) { 410 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "memcpy_s failed"); 411 return napi_generic_failure; 412 } 413 return napi_ok; 414 } 415 } 416 GetNativeValue(napi_env env,std::string type,napi_value valueNapi,EntryValue & value)417 bool GetNativeValue(napi_env env, std::string type, napi_value valueNapi, EntryValue &value) 418 { 419 bool isArrayBuffer = false; 420 NAPI_CALL_BASE(env, napi_is_arraybuffer(env, valueNapi, &isArrayBuffer), false); 421 if (isArrayBuffer) { 422 void *data = nullptr; 423 size_t dataLen = 0; 424 NAPI_CALL_BASE(env, napi_get_arraybuffer_info(env, valueNapi, &data, &dataLen), false); 425 value = std::vector<uint8_t>(reinterpret_cast<uint8_t *>(data), reinterpret_cast<uint8_t *>(data) + dataLen); 426 return true; 427 } 428 429 napi_status status; 430 napi_valuetype valueType = napi_undefined; 431 status = napi_typeof(env, valueNapi, &valueType); 432 NAPI_ASSERT_BASE(env, status == napi_ok, 433 "Parameter error: parameter value type must be ValueType", false); 434 if (valueType == napi_object) { 435 if (type == MIMETYPE_PIXELMAP) { 436 value = std::shared_ptr<OHOS::Media::PixelMap>(nullptr); 437 } else if (type == MIMETYPE_TEXT_WANT) { 438 value = std::shared_ptr<OHOS::AAFwk::Want>(nullptr); 439 } else { 440 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Parameter error: error ValueType"); 441 value = nullptr; 442 } 443 } else if (valueType == napi_string) { 444 value = std::string(); 445 } else if (valueType == napi_number) { 446 value = double(); 447 } else if (valueType == napi_boolean) { 448 value = bool(); 449 } else if (valueType == napi_undefined) { 450 value = std::monostate(); 451 } else if (valueType == napi_null) { 452 value = nullptr; 453 } 454 std::visit([&](auto &value) { status = NapiDataUtils::GetValue(env, valueNapi, value); }, value); 455 NAPI_ASSERT_BASE(env, status == napi_ok, "get unifiedRecord failed", false); 456 return true; 457 } 458 } // namespace MiscServicesNapi 459 } // namespace OHOS