1 /* 2 * Copyright (C) 2021-2022 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 #ifndef INTERFACES_KITS_JS_MEDIALIBRARY_INCLUDE_MEDIALIBRARY_NAPI_UTILS_H_ 17 #define INTERFACES_KITS_JS_MEDIALIBRARY_INCLUDE_MEDIALIBRARY_NAPI_UTILS_H_ 18 19 #include <tuple> 20 #include <memory> 21 #include <vector> 22 #include <unordered_map> 23 #include "datashare_result_set.h" 24 #include "napi/native_api.h" 25 #include "napi/native_node_api.h" 26 #include "hitrace_meter.h" 27 #include "medialibrary_client_errno.h" 28 #include "medialibrary_db_const.h" 29 #include "medialibrary_errno.h" 30 #include "medialibrary_napi_log.h" 31 #include "medialibrary_tracer.h" 32 #include "medialibrary_type_const.h" 33 #include "datashare_predicates.h" 34 35 #define GET_JS_ARGS(env, info, argc, argv, thisVar) \ 36 do { \ 37 void* data; \ 38 napi_get_cb_info(env, info, &(argc), argv, &(thisVar), &(data)); \ 39 } while (0) 40 41 #define GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar) \ 42 do { \ 43 void* data; \ 44 status = napi_get_cb_info(env, info, nullptr, nullptr, &(thisVar), &(data)); \ 45 } while (0) 46 47 #define GET_JS_ASYNC_CB_REF(env, arg, count, cbRef) \ 48 do { \ 49 napi_valuetype valueType = napi_undefined; \ 50 if ((napi_typeof(env, arg, &valueType) == napi_ok) && (valueType == napi_function)) { \ 51 napi_create_reference(env, arg, count, &(cbRef)); \ 52 } else { \ 53 NAPI_ERR_LOG("invalid arguments"); \ 54 NAPI_ASSERT(env, false, "type mismatch"); \ 55 } \ 56 } while (0) 57 58 #define ASSERT_NULLPTR_CHECK(env, result) \ 59 do { \ 60 if ((result) == nullptr) { \ 61 napi_get_undefined(env, &(result)); \ 62 return result; \ 63 } \ 64 } while (0) 65 66 #define NAPI_CREATE_PROMISE(env, callbackRef, deferred, result) \ 67 do { \ 68 if ((callbackRef) == nullptr) { \ 69 napi_create_promise(env, &(deferred), &(result)); \ 70 } \ 71 } while (0) 72 73 #define NAPI_CREATE_RESOURCE_NAME(env, resource, resourceName, context) \ 74 do { \ 75 napi_create_string_utf8(env, resourceName, NAPI_AUTO_LENGTH, &(resource)); \ 76 (context)->SetApiName(resourceName); \ 77 } while (0) 78 79 #define CHECK_NULL_PTR_RETURN_UNDEFINED(env, ptr, ret, message) \ 80 do { \ 81 if ((ptr) == nullptr) { \ 82 NAPI_ERR_LOG(message); \ 83 napi_get_undefined(env, &(ret)); \ 84 return ret; \ 85 } \ 86 } while (0) 87 88 #define CHECK_NULL_PTR_RETURN_VOID(ptr, message) \ 89 do { \ 90 if ((ptr) == nullptr) { \ 91 NAPI_ERR_LOG(message); \ 92 return; \ 93 } \ 94 } while (0) 95 #define CHECK_IF_EQUAL(condition, errMsg) \ 96 do { \ 97 if (!(condition)) { \ 98 NAPI_ERR_LOG(errMsg); \ 99 return; \ 100 } \ 101 } while (0) 102 103 #define CHECK_COND_RET(cond, ret, message) \ 104 do { \ 105 if (!(cond)) { \ 106 NAPI_ERR_LOG(message); \ 107 return ret; \ 108 } \ 109 } while (0) 110 111 #define CHECK_STATUS_RET(cond, message) \ 112 do { \ 113 napi_status __ret = (cond); \ 114 if (__ret != napi_ok) { \ 115 NAPI_ERR_LOG(message); \ 116 return __ret; \ 117 } \ 118 } while (0) 119 120 #define CHECK_ARGS(env, cond, context, err) \ 121 do { \ 122 if ((cond) != napi_ok) { \ 123 NAPI_THROW(env, context, err); \ 124 return nullptr; \ 125 } \ 126 } while (0) 127 128 #define NAPI_THROW(env, context, err) \ 129 do { \ 130 (context)->ThrowError(env, err); \ 131 } while (0) 132 133 namespace OHOS { 134 namespace Media { 135 /* Constants for array index */ 136 const int32_t PARAM0 = 0; 137 const int32_t PARAM1 = 1; 138 const int32_t PARAM2 = 2; 139 const int32_t PARAM3 = 3; 140 141 /* Constants for array size */ 142 const int32_t ARGS_ZERO = 0; 143 const int32_t ARGS_ONE = 1; 144 const int32_t ARGS_TWO = 2; 145 const int32_t ARGS_THREE = 3; 146 const int32_t ARGS_FOUR = 4; 147 const int32_t ARG_BUF_SIZE = 100; 148 constexpr uint32_t NAPI_INIT_REF_COUNT = 1; 149 150 constexpr size_t NAPI_ARGC_MAX = 4; 151 152 // Error codes 153 const int32_t ERR_DEFAULT = 0; 154 const int32_t ERR_MEM_ALLOCATION = 2; 155 const int32_t ERR_INVALID_OUTPUT = 3; 156 157 const int32_t TRASH_SMART_ALBUM_ID = 1; 158 const std::string TRASH_SMART_ALBUM_NAME = "TrashAlbum"; 159 const int32_t FAVORIT_SMART_ALBUM_ID = 2; 160 const std::string FAVORIT_SMART_ALBUM_NAME = "FavoritAlbum"; 161 162 enum NapiAssetType { 163 TYPE_AUDIO = 0, 164 TYPE_VIDEO = 1, 165 TYPE_IMAGE = 2, 166 TYPE_ALBUM = 3, 167 }; 168 169 enum AlbumType { 170 TYPE_VIDEO_ALBUM = 0, 171 TYPE_IMAGE_ALBUM = 1, 172 TYPE_NONE = 2, 173 }; 174 175 const std::vector<std::string> privateAlbumTypeNameEnum { 176 "TYPE_FAVORITE", "TYPE_TRASH", "TYPE_HIDE", "TYPE_SMART", "TYPE_SEARCH" 177 }; 178 179 const std::vector<std::string> mediaTypesEnum { 180 "FILE", "IMAGE", "VIDEO", "AUDIO", "MEDIA", "ALBUM_LIST", "ALBUM_LIST_INFO" 181 }; 182 183 const std::vector<std::string> mediaTypesUserFileEnum { 184 "IMAGE", "VIDEO", "AUDIO" 185 }; 186 187 const std::vector<std::string> fileKeyEnum { 188 "ID", "RELATIVE_PATH", "DISPLAY_NAME", "PARENT", "MIME_TYPE", "MEDIA_TYPE", "SIZE", 189 "DATE_ADDED", "DATE_MODIFIED", "DATE_TAKEN", "TITLE", "ARTIST", "AUDIOALBUM", "DURATION", 190 "WIDTH", "HEIGHT", "ORIENTATION", "ALBUM_ID", "ALBUM_NAME" 191 }; 192 193 const std::vector<std::string> directoryEnum { 194 "DIR_CAMERA", "DIR_VIDEO", "DIR_IMAGE", "DIR_AUDIO", "DIR_DOCUMENTS", "DIR_DOWNLOAD" 195 }; 196 197 const std::vector<std::string> virtualAlbumTypeEnum { 198 "TYPE_FAVORITE", "TYPE_TRASH" 199 }; 200 201 const std::vector<std::string> directoryEnumValues { 202 "Camera/", 203 "Videos/", 204 "Pictures/", 205 "Audios/", 206 "Documents/", 207 "Download/" 208 }; 209 210 const std::vector<std::string> fileKeyEnumValues { 211 MEDIA_DATA_DB_ID, 212 MEDIA_DATA_DB_RELATIVE_PATH, 213 MEDIA_DATA_DB_NAME, 214 MEDIA_DATA_DB_PARENT_ID, 215 MEDIA_DATA_DB_MIME_TYPE, 216 MEDIA_DATA_DB_MEDIA_TYPE, 217 MEDIA_DATA_DB_SIZE, 218 MEDIA_DATA_DB_DATE_ADDED, 219 MEDIA_DATA_DB_DATE_MODIFIED, 220 MEDIA_DATA_DB_DATE_TAKEN, 221 MEDIA_DATA_DB_TITLE, 222 MEDIA_DATA_DB_ARTIST, 223 MEDIA_DATA_DB_AUDIO_ALBUM, 224 MEDIA_DATA_DB_DURATION, 225 MEDIA_DATA_DB_WIDTH, 226 MEDIA_DATA_DB_HEIGHT, 227 MEDIA_DATA_DB_ORIENTATION, 228 MEDIA_DATA_DB_BUCKET_ID, 229 MEDIA_DATA_DB_BUCKET_NAME 230 }; 231 232 const std::vector<std::pair<std::string, std::string>> FILE_KEY_ENUM_PROPERTIES = { 233 std::make_pair("ID", MEDIA_DATA_DB_ID), 234 std::make_pair("RELATIVE_PATH", MEDIA_DATA_DB_RELATIVE_PATH), 235 std::make_pair("DISPLAY_NAME", MEDIA_DATA_DB_NAME), 236 std::make_pair("PARENT", MEDIA_DATA_DB_PARENT_ID), 237 std::make_pair("MIME_TYPE", MEDIA_DATA_DB_MIME_TYPE), 238 std::make_pair("MEDIA_TYPE", MEDIA_DATA_DB_MEDIA_TYPE), 239 std::make_pair("SIZE", MEDIA_DATA_DB_SIZE), 240 std::make_pair("DATE_ADDED", MEDIA_DATA_DB_DATE_ADDED), 241 std::make_pair("DATE_MODIFIED", MEDIA_DATA_DB_DATE_MODIFIED), 242 std::make_pair("DATE_TAKEN", MEDIA_DATA_DB_DATE_TAKEN), 243 std::make_pair("TITLE", MEDIA_DATA_DB_TITLE), 244 std::make_pair("ARTIST", MEDIA_DATA_DB_ARTIST), 245 std::make_pair("AUDIOALBUM", MEDIA_DATA_DB_AUDIO_ALBUM), 246 std::make_pair("DURATION", MEDIA_DATA_DB_DURATION), 247 std::make_pair("WIDTH", MEDIA_DATA_DB_WIDTH), 248 std::make_pair("HEIGHT", MEDIA_DATA_DB_HEIGHT), 249 std::make_pair("ORIENTATION", MEDIA_DATA_DB_ORIENTATION), 250 std::make_pair("ALBUM_ID", MEDIA_DATA_DB_BUCKET_ID), 251 std::make_pair("ALBUM_NAME", MEDIA_DATA_DB_BUCKET_NAME) 252 }; 253 254 const std::vector<std::pair<std::string, std::string>> USERFILEMGR_FILEKEY_ENUM_PROPERTIES = { 255 std::make_pair("URI", MEDIA_DATA_DB_URI), 256 std::make_pair("RELATIVE_PATH", MEDIA_DATA_DB_RELATIVE_PATH), 257 std::make_pair("DISPLAY_NAME", MEDIA_DATA_DB_NAME), 258 std::make_pair("DATE_ADDED", MEDIA_DATA_DB_DATE_ADDED), 259 std::make_pair("DATE_MODIFIED", MEDIA_DATA_DB_DATE_MODIFIED), 260 std::make_pair("TITLE", MEDIA_DATA_DB_TITLE) 261 }; 262 263 const std::vector<std::pair<std::string, std::string>> AUDIOKEY_ENUM_PROPERTIES = { 264 std::make_pair("URI", MEDIA_DATA_DB_URI), 265 std::make_pair("DISPLAY_NAME", MEDIA_DATA_DB_NAME), 266 std::make_pair("DATE_ADDED", MEDIA_DATA_DB_DATE_ADDED), 267 std::make_pair("DATE_MODIFIED", MEDIA_DATA_DB_DATE_MODIFIED), 268 std::make_pair("TITLE", MEDIA_DATA_DB_TITLE), 269 std::make_pair("ARTIST", MEDIA_DATA_DB_ARTIST), 270 std::make_pair("AUDIOALBUM", MEDIA_DATA_DB_AUDIO_ALBUM), 271 std::make_pair("DURATION", MEDIA_DATA_DB_DURATION), 272 std::make_pair("FAVORITE", MEDIA_DATA_DB_IS_FAV) 273 }; 274 275 const std::vector<std::pair<std::string, std::string>> IMAGEVIDEOKEY_ENUM_PROPERTIES = { 276 std::make_pair("URI", MEDIA_DATA_DB_URI), 277 std::make_pair("DISPLAY_NAME", MEDIA_DATA_DB_NAME), 278 std::make_pair("DATE_ADDED", MEDIA_DATA_DB_DATE_ADDED), 279 std::make_pair("FILE_TYPE", MEDIA_DATA_DB_MEDIA_TYPE), 280 std::make_pair("DATE_MODIFIED", MEDIA_DATA_DB_DATE_MODIFIED), 281 std::make_pair("TITLE", MEDIA_DATA_DB_TITLE), 282 std::make_pair("DURATION", MEDIA_DATA_DB_DURATION), 283 std::make_pair("WIDTH", MEDIA_DATA_DB_WIDTH), 284 std::make_pair("HEIGHT", MEDIA_DATA_DB_HEIGHT), 285 std::make_pair("DATE_TAKEN", MEDIA_DATA_DB_DATE_TAKEN), 286 std::make_pair("ORIENTATION", MEDIA_DATA_DB_ORIENTATION), 287 std::make_pair("FAVORITE", MEDIA_DATA_DB_IS_FAV), 288 std::make_pair("MEDIA_TYPE", MEDIA_DATA_DB_MEDIA_TYPE) 289 }; 290 291 const std::vector<std::pair<std::string, std::string>> ALBUMKEY_ENUM_PROPERTIES = { 292 std::make_pair("URI", MEDIA_DATA_DB_URI), 293 std::make_pair("ALBUM_NAME", MEDIA_DATA_DB_BUCKET_NAME), 294 std::make_pair("FILE_TYPE", MEDIA_DATA_DB_MEDIA_TYPE), 295 std::make_pair("DATE_ADDED", MEDIA_DATA_DB_DATE_ADDED), 296 std::make_pair("DATE_MODIFIED", MEDIA_DATA_DB_DATE_MODIFIED) 297 }; 298 299 struct JSAsyncContextOutput { 300 napi_value error; 301 napi_value data; 302 bool status; 303 }; 304 305 struct NapiClassInfo { 306 std::string name; 307 napi_ref *ref; 308 napi_value (*constructor)(napi_env, napi_callback_info); 309 std::vector<napi_property_descriptor> props; 310 }; 311 312 /* Util class used by napi asynchronous methods for making call to js callback function */ 313 class MediaLibraryNapiUtils { 314 public: 315 static napi_value NapiDefineClass(napi_env env, napi_value exports, const NapiClassInfo &info); 316 static napi_value NapiAddStaticProps(napi_env env, napi_value exports, 317 const std::vector<napi_property_descriptor> &staticProps); 318 319 static napi_status GetUInt32(napi_env env, napi_value arg, uint32_t &value); 320 static napi_status GetInt32(napi_env env, napi_value arg, int32_t &value); 321 static napi_status GetParamBool(napi_env env, napi_value arg, bool &result); 322 static napi_status GetUInt32Array(napi_env env, napi_value arg, std::vector<uint32_t> ¶m); 323 static napi_status GetParamFunction(napi_env env, napi_value arg, napi_ref &callbackRef); 324 static napi_status GetParamString(napi_env env, napi_value arg, std::string &str); 325 static napi_status GetParamStringPathMax(napi_env env, napi_value arg, std::string &str); 326 static napi_status GetProperty(napi_env env, const napi_value arg, const std::string &propName, 327 std::string &propValue); 328 static napi_status GetArrayProperty(napi_env env, napi_value arg, const std::string &propName, 329 std::vector<std::string> &array); 330 static void GenTypeMaskFromArray(const std::vector<uint32_t> types, std::string &typeMask); 331 static void UriAddFragmentTypeMask(std::string &uri, const std::string &typeMask); 332 static void UriRemoveAllFragment(std::string &uri); 333 static std::string GetFileIdFromUri(const std::string &uri); 334 static MediaType GetMediaTypeFromUri(const std::string &uri); 335 template <class AsyncContext> 336 static napi_status GetPredicate(napi_env env, const napi_value arg, const std::string &propName, 337 AsyncContext &context, bool isAlbum); 338 template <class AsyncContext> 339 static napi_status ParseAlbumFetchOptCallback(napi_env env, napi_callback_info info, AsyncContext &context); 340 template <class AsyncContext> 341 static bool HandleSpecialPredicate(AsyncContext &context, 342 std::shared_ptr<DataShare::DataShareAbsPredicates> &predicate, bool isAlbum); 343 template <class AsyncContext> 344 static void UpdateMediaTypeSelections(AsyncContext *context); 345 static void GetNetworkIdAndFileIdFromUri(const std::string &uri, std::string &networkId, std::string &fileId); 346 347 template <class AsyncContext> AsyncContextSetObjectInfo(napi_env env,napi_callback_info info,AsyncContext & asyncContext,const size_t minArgs,const size_t maxArgs)348 static napi_status AsyncContextSetObjectInfo(napi_env env, napi_callback_info info, AsyncContext &asyncContext, 349 const size_t minArgs, const size_t maxArgs) 350 { 351 napi_value thisVar = nullptr; 352 asyncContext->argc = maxArgs; 353 CHECK_STATUS_RET(napi_get_cb_info(env, info, &asyncContext->argc, &(asyncContext->argv[ARGS_ZERO]), &thisVar, 354 nullptr), "Failed to get cb info"); 355 CHECK_COND_RET(((asyncContext->argc >= minArgs) && (asyncContext->argc <= maxArgs)), napi_invalid_arg, 356 "Number of args is invalid"); 357 if (minArgs > 0) { 358 CHECK_COND_RET(asyncContext->argv[ARGS_ZERO] != nullptr, napi_invalid_arg, "Argument list is empty"); 359 } 360 CHECK_STATUS_RET(napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo)), 361 "Failed to unwrap thisVar"); 362 CHECK_COND_RET(asyncContext->objectInfo != nullptr, napi_invalid_arg, "Failed to get object info"); 363 return napi_ok; 364 } 365 366 template <class AsyncContext> GetFetchOption(napi_env env,napi_value arg,AsyncContext & context)367 static napi_status GetFetchOption(napi_env env, napi_value arg, AsyncContext &context) 368 { 369 /* Parse the argument into fetchOption if any */ 370 bool hasOpt = false; 371 CHECK_STATUS_RET(hasFetchOpt(env, arg, hasOpt), "Failed to get fetchopt"); 372 if (hasOpt) { 373 CHECK_STATUS_RET(GetProperty(env, arg, "selections", context->selection), "Failed to parse selections"); 374 CHECK_STATUS_RET(GetProperty(env, arg, "order", context->order), "Failed to parse order"); 375 CHECK_STATUS_RET(GetArrayProperty(env, arg, "selectionArgs", context->selectionArgs), 376 "Failed to parse selectionArgs"); 377 CHECK_STATUS_RET(GetProperty(env, arg, "uri", context->uri), "Failed to parse uri"); 378 CHECK_STATUS_RET(GetProperty(env, arg, "networkId", context->networkId), "Failed to parse networkId"); 379 } 380 return napi_ok; 381 } 382 383 template <class AsyncContext> 384 static napi_status GetAssetFetchOption(napi_env env, napi_value arg, AsyncContext &context); 385 386 template <class AsyncContext> GetParamCallback(napi_env env,AsyncContext & context)387 static napi_status GetParamCallback(napi_env env, AsyncContext &context) 388 { 389 /* Parse the last argument into callbackref if any */ 390 bool isCallback = false; 391 CHECK_STATUS_RET(hasCallback(env, context->argc, context->argv, isCallback), "Failed to check callback"); 392 if (isCallback) { 393 CHECK_STATUS_RET(GetParamFunction(env, context->argv[context->argc - 1], context->callbackRef), 394 "Failed to get callback"); 395 } 396 return napi_ok; 397 } 398 399 template <class AsyncContext> 400 static napi_status ParseAssetFetchOptCallback(napi_env env, napi_callback_info info, 401 AsyncContext &context); 402 403 template <class AsyncContext> ParseArgsTypeFetchOptCallback(napi_env env,napi_callback_info info,AsyncContext & context)404 static napi_status ParseArgsTypeFetchOptCallback(napi_env env, napi_callback_info info, AsyncContext &context) 405 { 406 constexpr size_t minArgs = ARGS_TWO; 407 constexpr size_t maxArgs = ARGS_THREE; 408 CHECK_STATUS_RET(AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs), 409 "Failed to get object info"); 410 /* Parse the first argument into typeMask */ 411 CHECK_STATUS_RET(GetUInt32Array(env, context->argv[ARGS_ZERO], context->mediaTypes), 412 "Failed to get param array"); 413 CHECK_COND_RET(context->mediaTypes.size() > 0, napi_invalid_arg, "Require at least one type"); 414 GenTypeMaskFromArray(context->mediaTypes, context->typeMask); 415 CHECK_STATUS_RET(GetFetchOption(env, context->argv[ARGS_ONE], context), "Failed to get fetch option"); 416 CHECK_STATUS_RET(GetParamCallback(env, context), "Failed to get callback"); 417 return napi_ok; 418 } 419 420 template <class AsyncContext> ParseArgsBoolCallBack(napi_env env,napi_callback_info info,AsyncContext & context,bool & param)421 static napi_status ParseArgsBoolCallBack(napi_env env, napi_callback_info info, AsyncContext &context, bool ¶m) 422 { 423 constexpr size_t minArgs = ARGS_ONE; 424 constexpr size_t maxArgs = ARGS_TWO; 425 CHECK_STATUS_RET(AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs), 426 "Failed to get object info"); 427 428 /* Parse the first argument into param */ 429 CHECK_STATUS_RET(GetParamBool(env, context->argv[ARGS_ZERO], param), "Failed to get parameter"); 430 CHECK_STATUS_RET(GetParamCallback(env, context), "Failed to get callback"); 431 return napi_ok; 432 } 433 434 template <class AsyncContext> ParseArgsStringCallback(napi_env env,napi_callback_info info,AsyncContext & context,std::string & param)435 static napi_status ParseArgsStringCallback(napi_env env, napi_callback_info info, AsyncContext &context, 436 std::string ¶m) 437 { 438 constexpr size_t minArgs = ARGS_ONE; 439 constexpr size_t maxArgs = ARGS_TWO; 440 CHECK_STATUS_RET(AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs), 441 "Failed to get object info"); 442 443 CHECK_STATUS_RET(GetParamStringPathMax(env, context->argv[ARGS_ZERO], param), "Failed to get string argument"); 444 CHECK_STATUS_RET(GetParamCallback(env, context), "Failed to get callback"); 445 return napi_ok; 446 } 447 448 template <class AsyncContext> ParseArgsNumberCallback(napi_env env,napi_callback_info info,AsyncContext & context,int32_t & value)449 static napi_status ParseArgsNumberCallback(napi_env env, napi_callback_info info, AsyncContext &context, 450 int32_t &value) 451 { 452 constexpr size_t minArgs = ARGS_ONE; 453 constexpr size_t maxArgs = ARGS_TWO; 454 CHECK_STATUS_RET(AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs), 455 "Failed to get object info"); 456 457 CHECK_STATUS_RET(GetInt32(env, context->argv[ARGS_ZERO], value), "Failed to get number argument"); 458 CHECK_STATUS_RET(GetParamCallback(env, context), "Failed to get callback"); 459 return napi_ok; 460 } 461 462 template <class AsyncContext> ParseArgsOnlyCallBack(napi_env env,napi_callback_info info,AsyncContext & context)463 static napi_status ParseArgsOnlyCallBack(napi_env env, napi_callback_info info, AsyncContext &context) 464 { 465 constexpr size_t minArgs = ARGS_ZERO; 466 constexpr size_t maxArgs = ARGS_ONE; 467 CHECK_STATUS_RET(AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs), 468 "Failed to get object info"); 469 470 CHECK_STATUS_RET(GetParamCallback(env, context), "Failed to get callback"); 471 return napi_ok; 472 } 473 GetAssetType(MediaType type)474 static AssetType GetAssetType(MediaType type) 475 { 476 AssetType result; 477 478 switch (type) { 479 case MEDIA_TYPE_AUDIO: 480 result = ASSET_AUDIO; 481 break; 482 case MEDIA_TYPE_VIDEO: 483 result = ASSET_VIDEO; 484 break; 485 case MEDIA_TYPE_IMAGE: 486 result = ASSET_IMAGE; 487 break; 488 case MEDIA_TYPE_MEDIA: 489 result = ASSET_MEDIA; 490 break; 491 default: 492 result = ASSET_NONE; 493 break; 494 } 495 496 return result; 497 } 498 AppendFetchOptionSelection(std::string & selection,const std::string & newCondition)499 static void AppendFetchOptionSelection(std::string &selection, const std::string &newCondition) 500 { 501 if (!newCondition.empty()) { 502 if (!selection.empty()) { 503 selection = "(" + selection + ") AND " + newCondition; 504 } else { 505 selection = newCondition; 506 } 507 } 508 } 509 GetMediaTypeUri(MediaType mediaType)510 static std::string GetMediaTypeUri(MediaType mediaType) 511 { 512 switch (mediaType) { 513 case MEDIA_TYPE_AUDIO: 514 return MEDIALIBRARY_AUDIO_URI; 515 case MEDIA_TYPE_VIDEO: 516 return MEDIALIBRARY_VIDEO_URI; 517 case MEDIA_TYPE_IMAGE: 518 return MEDIALIBRARY_IMAGE_URI; 519 case MEDIA_TYPE_SMARTALBUM: 520 return MEDIALIBRARY_SMARTALBUM_CHANGE_URI; 521 case MEDIA_TYPE_DEVICE: 522 return MEDIALIBRARY_DEVICE_URI; 523 case MEDIA_TYPE_FILE: 524 default: 525 return MEDIALIBRARY_FILE_URI; 526 } 527 } 528 TransErrorCode(const std::string & Name,std::shared_ptr<DataShare::DataShareResultSet> resultSet)529 static int TransErrorCode(const std::string &Name, std::shared_ptr<DataShare::DataShareResultSet> resultSet) 530 { 531 NAPI_ERR_LOG("interface: %{public}s, server return nullptr", Name.c_str()); 532 // Query can't return errorcode, so assume nullptr as permission deny 533 if (resultSet == nullptr) { 534 return JS_ERR_PERMISSION_DENIED; 535 } 536 return ERR_DEFAULT; 537 } 538 TransErrorCode(const std::string & Name,int error)539 static int TransErrorCode(const std::string &Name, int error) 540 { 541 NAPI_ERR_LOG("interface: %{public}s, server errcode:%{public}d ", Name.c_str(), error); 542 // Transfer Server error to napi error code 543 if (error <= E_COMMON_START && error >= E_COMMON_END) { 544 error = JS_INNER_FAIL; 545 } else if (trans2JsError.count(error)) { 546 error = trans2JsError.at(error); 547 } 548 return error; 549 } 550 HandleError(napi_env env,int error,napi_value & errorObj,const std::string & Name)551 static void HandleError(napi_env env, int error, napi_value &errorObj, const std::string &Name) 552 { 553 if (error == ERR_DEFAULT) { 554 return; 555 } 556 557 std::string errMsg = "operation fail"; 558 if (jsErrMap.count(error) > 0) { 559 errMsg = jsErrMap.at(error); 560 } 561 CreateNapiErrorObject(env, errorObj, error, errMsg); 562 errMsg = Name + " " + errMsg; 563 NAPI_ERR_LOG("Error: %{public}s, js errcode:%{public}d ", errMsg.c_str(), error); 564 } 565 CreateNapiErrorObject(napi_env env,napi_value & errorObj,const int32_t errCode,const std::string errMsg)566 static void CreateNapiErrorObject(napi_env env, napi_value &errorObj, 567 const int32_t errCode, const std::string errMsg) 568 { 569 napi_status statusError; 570 napi_value napiErrorCode = nullptr; 571 napi_value napiErrorMsg = nullptr; 572 statusError = napi_create_string_utf8(env, std::to_string(errCode).c_str(), NAPI_AUTO_LENGTH, &napiErrorCode); 573 if (statusError == napi_ok) { 574 statusError = napi_create_string_utf8(env, errMsg.c_str(), NAPI_AUTO_LENGTH, &napiErrorMsg); 575 if (statusError == napi_ok) { 576 statusError = napi_create_error(env, napiErrorCode, napiErrorMsg, &errorObj); 577 if (statusError == napi_ok) { 578 NAPI_DEBUG_LOG("napi_create_error success"); 579 } 580 } 581 } 582 } 583 InvokeJSAsyncMethod(napi_env env,napi_deferred deferred,napi_ref callbackRef,napi_async_work work,const JSAsyncContextOutput & asyncContext)584 static void InvokeJSAsyncMethod(napi_env env, napi_deferred deferred, 585 napi_ref callbackRef, napi_async_work work, const JSAsyncContextOutput &asyncContext) 586 { 587 MediaLibraryTracer tracer; 588 tracer.Start("InvokeJSAsyncMethod"); 589 590 NAPI_DEBUG_LOG("InvokeJSAsyncMethod IN"); 591 napi_value retVal; 592 napi_value callback = nullptr; 593 594 /* Deferred is used when JS Callback method expects a promise value */ 595 if (deferred) { 596 NAPI_DEBUG_LOG("InvokeJSAsyncMethod promise"); 597 if (asyncContext.status) { 598 napi_resolve_deferred(env, deferred, asyncContext.data); 599 } else { 600 napi_reject_deferred(env, deferred, asyncContext.error); 601 } 602 } else { 603 NAPI_DEBUG_LOG("InvokeJSAsyncMethod callback"); 604 napi_value result[ARGS_TWO]; 605 result[PARAM0] = asyncContext.error; 606 result[PARAM1] = asyncContext.data; 607 napi_get_reference_value(env, callbackRef, &callback); 608 napi_call_function(env, nullptr, callback, ARGS_TWO, result, &retVal); 609 napi_delete_reference(env, callbackRef); 610 } 611 napi_delete_async_work(env, work); 612 NAPI_DEBUG_LOG("InvokeJSAsyncMethod OUT"); 613 } 614 615 template <class AsyncContext> NapiCreateAsyncWork(napi_env env,std::unique_ptr<AsyncContext> & asyncContext,const std::string & resourceName,void (* execute)(napi_env,void *),void (* complete)(napi_env,napi_status,void *))616 static napi_value NapiCreateAsyncWork(napi_env env, std::unique_ptr<AsyncContext> &asyncContext, 617 const std::string &resourceName, void (*execute)(napi_env, void *), 618 void (*complete)(napi_env, napi_status, void *)) 619 { 620 napi_value result = nullptr; 621 napi_value resource = nullptr; 622 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result); 623 NAPI_CREATE_RESOURCE_NAME(env, resource, resourceName.c_str(), asyncContext); 624 625 NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, execute, complete, 626 static_cast<void*>(asyncContext.get()), &asyncContext->work)); 627 NAPI_CALL(env, napi_queue_async_work(env, asyncContext->work)); 628 asyncContext.release(); 629 630 return result; 631 } 632 ToUTF8String(napi_env env,napi_value value)633 static std::tuple<bool, std::unique_ptr<char[]>, size_t> ToUTF8String(napi_env env, napi_value value) 634 { 635 size_t strLen = 0; 636 napi_status status = napi_get_value_string_utf8(env, value, nullptr, -1, &strLen); 637 if (status != napi_ok) { 638 NAPI_ERR_LOG("ToUTF8String get fail, %{public}d", status); 639 return { false, nullptr, 0 }; 640 } 641 642 size_t bufLen = strLen + 1; 643 std::unique_ptr<char[]> str = std::make_unique<char[]>(bufLen); 644 if (str == nullptr) { 645 NAPI_ERR_LOG("ToUTF8String get memory fail"); 646 return { false, nullptr, 0 }; 647 } 648 status = napi_get_value_string_utf8(env, value, str.get(), bufLen, &strLen); 649 return std::make_tuple(status == napi_ok, move(str), strLen); 650 } 651 IsExistsByPropertyName(napi_env env,napi_value jsObject,const char * propertyName)652 static bool IsExistsByPropertyName(napi_env env, napi_value jsObject, const char *propertyName) 653 { 654 bool result = false; 655 if (napi_has_named_property(env, jsObject, propertyName, &result) == napi_ok) { 656 return result; 657 } else { 658 NAPI_ERR_LOG("IsExistsByPropertyName not exist %{public}s", propertyName); 659 return false; 660 } 661 } 662 GetPropertyValueByName(napi_env env,napi_value jsObject,const char * propertyName)663 static napi_value GetPropertyValueByName(napi_env env, napi_value jsObject, const char *propertyName) 664 { 665 napi_value value = nullptr; 666 if (IsExistsByPropertyName(env, jsObject, propertyName) == false) { 667 NAPI_ERR_LOG("GetPropertyValueByName not exist %{public}s", propertyName); 668 return nullptr; 669 } 670 if (napi_get_named_property(env, jsObject, propertyName, &value) != napi_ok) { 671 NAPI_ERR_LOG("GetPropertyValueByName get fail %{public}s", propertyName); 672 return nullptr; 673 } 674 return value; 675 } 676 CheckJSArgsTypeAsFunc(napi_env env,napi_value arg)677 static bool CheckJSArgsTypeAsFunc(napi_env env, napi_value arg) 678 { 679 napi_valuetype valueType = napi_undefined; 680 napi_typeof(env, arg, &valueType); 681 return (valueType == napi_function); 682 } 683 IsArrayForNapiValue(napi_env env,napi_value param,uint32_t & arraySize)684 static bool IsArrayForNapiValue(napi_env env, napi_value param, uint32_t &arraySize) 685 { 686 bool isArray = false; 687 arraySize = 0; 688 if ((napi_is_array(env, param, &isArray) != napi_ok) || (isArray == false)) { 689 return false; 690 } 691 if (napi_get_array_length(env, param, &arraySize) != napi_ok) { 692 return false; 693 } 694 return true; 695 } 696 private: 697 static napi_status hasCallback(napi_env env, const size_t argc, const napi_value argv[], 698 bool &isCallback); 699 static napi_status hasFetchOpt(napi_env env, const napi_value arg, bool &hasFetchOpt); 700 }; 701 } // namespace Media 702 } // namespace OHOS 703 704 #endif // INTERFACES_KITS_JS_MEDIALIBRARY_INCLUDE_MEDIALIBRARY_NAPI_UTILS_H_ 705