• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "userfile_manager_types.h"
16 #define MLOG_TAG "FileAssetNapi"
17 
18 #include "file_asset_napi.h"
19 
20 #include <algorithm>
21 #include <cstring>
22 #include <fcntl.h>
23 #include <unistd.h>
24 #include <sys/stat.h>
25 
26 #include "abs_shared_result_set.h"
27 #include "access_token.h"
28 #include "accesstoken_kit.h"
29 #include "datashare_errno.h"
30 #include "datashare_predicates.h"
31 #include "datashare_result_set.h"
32 #include "datashare_values_bucket.h"
33 #include "hitrace_meter.h"
34 #include "fetch_result.h"
35 #include "file_uri.h"
36 #include "hilog/log.h"
37 #include "ipc_skeleton.h"
38 #include "js_native_api.h"
39 #include "js_native_api_types.h"
40 #include "location_column.h"
41 #include "locale_config.h"
42 #include "media_asset_edit_data_napi.h"
43 #include "media_exif.h"
44 #include "media_column.h"
45 #include "media_file_utils.h"
46 #include "media_file_uri.h"
47 #include "medialibrary_client_errno.h"
48 #include "medialibrary_db_const.h"
49 #include "medialibrary_errno.h"
50 #include "medialibrary_napi_log.h"
51 #include "medialibrary_napi_utils.h"
52 #include "medialibrary_tracer.h"
53 #include "nlohmann/json.hpp"
54 #include "post_proc.h"
55 #include "rdb_errno.h"
56 #include "sandbox_helper.h"
57 #include "string_ex.h"
58 #include "thumbnail_const.h"
59 #include "thumbnail_utils.h"
60 #include "unique_fd.h"
61 #include "userfile_client.h"
62 #include "userfilemgr_uri.h"
63 #include "vision_column.h"
64 
65 using OHOS::HiviewDFX::HiLog;
66 using OHOS::HiviewDFX::HiLogLabel;
67 using namespace std;
68 using namespace OHOS::AppExecFwk;
69 using namespace OHOS::NativeRdb;
70 using namespace OHOS::DataShare;
71 using namespace OHOS::Security::AccessToken;
72 using std::string;
73 
74 namespace OHOS {
75 namespace Media {
76 static const std::string MEDIA_FILEDESCRIPTOR = "fd";
77 static const std::string MEDIA_FILEMODE = "mode";
78 
79 thread_local napi_ref FileAssetNapi::sConstructor_ = nullptr;
80 thread_local std::shared_ptr<FileAsset> FileAssetNapi::sFileAsset_ = nullptr;
81 shared_ptr<ThumbnailManager> FileAssetNapi::thumbnailManager_ = nullptr;
82 
83 constexpr int32_t IS_TRASH = 1;
84 constexpr int32_t NOT_TRASH = 0;
85 
86 constexpr int32_t IS_FAV = 1;
87 constexpr int32_t NOT_FAV = 0;
88 
89 constexpr int32_t IS_HIDDEN = 1;
90 constexpr int32_t NOT_HIDDEN = 0;
91 
92 constexpr int32_t USER_COMMENT_MAX_LEN = 420;
93 
94 using CompleteCallback = napi_async_complete_callback;
95 
96 thread_local napi_ref FileAssetNapi::userFileMgrConstructor_ = nullptr;
97 thread_local napi_ref FileAssetNapi::photoAccessHelperConstructor_ = nullptr;
98 
99 class TransferFileAsset {
100 public:
101     std::shared_ptr<FileAsset> fileAsset = nullptr;
102     ~TransferFileAsset() = default;
103 };
104 
FileAssetNapi()105 FileAssetNapi::FileAssetNapi()
106     : env_(nullptr) {}
107 
108 FileAssetNapi::~FileAssetNapi() = default;
109 
FileAssetNapiDestructor(napi_env env,void * nativeObject,void * finalize_hint)110 void FileAssetNapi::FileAssetNapiDestructor(napi_env env, void *nativeObject, void *finalize_hint)
111 {
112     FileAssetNapi *fileAssetObj = reinterpret_cast<FileAssetNapi*>(nativeObject);
113     if (fileAssetObj != nullptr) {
114         NAPI_DEBUG_LOG("Destroying native asset object ID: %{public}d",
115             fileAssetObj != nullptr ? fileAssetObj->GetFileId() : -1);
116         delete fileAssetObj;
117         fileAssetObj = nullptr;
118     }
119 }
120 
GetExports(napi_env & env,napi_value & exports,napi_property_descriptor * file_asset_props,int32_t fileAssetPropsSize)121 napi_value FileAssetNapi::GetExports(napi_env &env, napi_value &exports, napi_property_descriptor *file_asset_props,
122     int32_t fileAssetPropsSize)
123 {
124     napi_status status;
125     napi_value ctorObj;
126     int32_t refCount = 1;
127     status = napi_define_class(env, FILE_ASSET_NAPI_CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, FileAssetNapiConstructor,
128         nullptr, fileAssetPropsSize, file_asset_props, &ctorObj);
129     if (status == napi_ok) {
130         status = napi_create_reference(env, ctorObj, refCount, &sConstructor_);
131         if (status == napi_ok) {
132             status = napi_set_named_property(env, exports, FILE_ASSET_NAPI_CLASS_NAME.c_str(), ctorObj);
133             if (status == napi_ok) {
134                 return exports;
135             }
136         }
137     }
138     return nullptr;
139 }
140 
Init(napi_env env,napi_value exports)141 napi_value FileAssetNapi::Init(napi_env env, napi_value exports)
142 {
143     napi_property_descriptor file_asset_props[] = {
144         DECLARE_NAPI_GETTER("id", JSGetFileId),
145         DECLARE_NAPI_GETTER("uri", JSGetFileUri),
146         DECLARE_NAPI_GETTER("mediaType", JSGetMediaType),
147         DECLARE_NAPI_GETTER_SETTER("displayName", JSGetFileDisplayName, JSSetFileDisplayName),
148         DECLARE_NAPI_GETTER_SETTER("relativePath", JSGetRelativePath, JSSetRelativePath),
149         DECLARE_NAPI_GETTER("parent", JSParent),
150         DECLARE_NAPI_GETTER("size", JSGetSize),
151         DECLARE_NAPI_GETTER("dateAdded", JSGetDateAdded),
152         DECLARE_NAPI_GETTER("dateTrashed", JSGetDateTrashed),
153         DECLARE_NAPI_GETTER("dateModified", JSGetDateModified),
154         DECLARE_NAPI_GETTER("dateTaken", JSGetDateTaken),
155         DECLARE_NAPI_GETTER("mimeType", JSGetMimeType),
156         DECLARE_NAPI_GETTER_SETTER("title", JSGetTitle, JSSetTitle),
157         DECLARE_NAPI_GETTER("artist", JSGetArtist),
158         DECLARE_NAPI_GETTER("audioAlbum", JSGetAlbum),
159         DECLARE_NAPI_GETTER("width", JSGetWidth),
160         DECLARE_NAPI_GETTER("height", JSGetHeight),
161         DECLARE_NAPI_GETTER_SETTER("orientation", JSGetOrientation, JSSetOrientation),
162         DECLARE_NAPI_GETTER("duration", JSGetDuration),
163         DECLARE_NAPI_GETTER("albumId", JSGetAlbumId),
164         DECLARE_NAPI_GETTER("albumUri", JSGetAlbumUri),
165         DECLARE_NAPI_GETTER("albumName", JSGetAlbumName),
166         DECLARE_NAPI_GETTER("count", JSGetCount),
167         DECLARE_NAPI_FUNCTION("isDirectory", JSIsDirectory),
168         DECLARE_NAPI_FUNCTION("commitModify", JSCommitModify),
169         DECLARE_NAPI_FUNCTION("open", JSOpen),
170         DECLARE_NAPI_FUNCTION("close", JSClose),
171         DECLARE_NAPI_FUNCTION("getThumbnail", JSGetThumbnail),
172         DECLARE_NAPI_FUNCTION("favorite", JSFavorite),
173         DECLARE_NAPI_FUNCTION("isFavorite", JSIsFavorite),
174         DECLARE_NAPI_FUNCTION("trash", JSTrash),
175         DECLARE_NAPI_FUNCTION("isTrash", JSIsTrash),
176     };
177     int32_t fileAssetPropsSize = sizeof(file_asset_props) / sizeof(file_asset_props[PARAM0]);
178     napi_value exportsValue = GetExports(env, exports, file_asset_props, fileAssetPropsSize);
179     if (exportsValue != nullptr) {
180         return exportsValue;
181     }
182     return nullptr;
183 }
184 
UserFileMgrInit(napi_env env,napi_value exports)185 napi_value FileAssetNapi::UserFileMgrInit(napi_env env, napi_value exports)
186 {
187     NapiClassInfo info = {
188         .name = USERFILEMGR_FILEASSET_NAPI_CLASS_NAME,
189         .ref = &userFileMgrConstructor_,
190         .constructor = FileAssetNapiConstructor,
191         .props = {
192             DECLARE_NAPI_FUNCTION("get", UserFileMgrGet),
193             DECLARE_NAPI_FUNCTION("set", UserFileMgrSet),
194             DECLARE_NAPI_FUNCTION("open", UserFileMgrOpen),
195             DECLARE_NAPI_FUNCTION("close", UserFileMgrClose),
196             DECLARE_NAPI_FUNCTION("commitModify", UserFileMgrCommitModify),
197             DECLARE_NAPI_FUNCTION("favorite", UserFileMgrFavorite),
198             DECLARE_NAPI_GETTER("uri", JSGetFileUri),
199             DECLARE_NAPI_GETTER("fileType", JSGetMediaType),
200             DECLARE_NAPI_GETTER_SETTER("displayName", JSGetFileDisplayName, JSSetFileDisplayName),
201             DECLARE_NAPI_FUNCTION("getThumbnail", UserFileMgrGetThumbnail),
202             DECLARE_NAPI_FUNCTION("getReadOnlyFd", JSGetReadOnlyFd),
203             DECLARE_NAPI_FUNCTION("setHidden", UserFileMgrSetHidden),
204             DECLARE_NAPI_FUNCTION("setPending", UserFileMgrSetPending),
205             DECLARE_NAPI_FUNCTION("getExif", JSGetExif),
206             DECLARE_NAPI_FUNCTION("setUserComment", UserFileMgrSetUserComment),
207             DECLARE_NAPI_GETTER("count", JSGetCount),
208             DECLARE_NAPI_FUNCTION("getJson", UserFileMgrGetJson),
209         }
210     };
211     MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
212 
213     return exports;
214 }
215 
PhotoAccessHelperInit(napi_env env,napi_value exports)216 napi_value FileAssetNapi::PhotoAccessHelperInit(napi_env env, napi_value exports)
217 {
218     NapiClassInfo info = {
219         .name = PHOTOACCESSHELPER_FILEASSET_NAPI_CLASS_NAME,
220         .ref = &photoAccessHelperConstructor_,
221         .constructor = FileAssetNapiConstructor,
222         .props = {
223             DECLARE_NAPI_FUNCTION("get", UserFileMgrGet),
224             DECLARE_NAPI_FUNCTION("set", UserFileMgrSet),
225             DECLARE_NAPI_FUNCTION("open", PhotoAccessHelperOpen),
226             DECLARE_NAPI_FUNCTION("close", PhotoAccessHelperClose),
227             DECLARE_NAPI_FUNCTION("commitModify", PhotoAccessHelperCommitModify),
228             DECLARE_NAPI_FUNCTION("setFavorite", PhotoAccessHelperFavorite),
229             DECLARE_NAPI_GETTER("uri", JSGetFileUri),
230             DECLARE_NAPI_GETTER("photoType", JSGetMediaType),
231             DECLARE_NAPI_GETTER_SETTER("displayName", JSGetFileDisplayName, JSSetFileDisplayName),
232             DECLARE_NAPI_FUNCTION("getThumbnail", PhotoAccessHelperGetThumbnail),
233             DECLARE_NAPI_FUNCTION("getReadOnlyFd", JSGetReadOnlyFd),
234             DECLARE_NAPI_FUNCTION("setHidden", PhotoAccessHelperSetHidden),
235             DECLARE_NAPI_FUNCTION("setPending", PhotoAccessHelperSetPending),
236             DECLARE_NAPI_FUNCTION("getExif", JSGetExif),
237             DECLARE_NAPI_FUNCTION("setUserComment", PhotoAccessHelperSetUserComment),
238             DECLARE_NAPI_FUNCTION("requestPhoto", PhotoAccessHelperRequestPhoto),
239             DECLARE_NAPI_FUNCTION("cancelPhotoRequest", PhotoAccessHelperCancelPhotoRequest),
240             DECLARE_NAPI_FUNCTION("isEdited", PhotoAccessHelperIsEdited),
241             DECLARE_NAPI_FUNCTION("requestEditData", PhotoAccessHelperRequestEditData),
242             DECLARE_NAPI_FUNCTION("requestSource", PhotoAccessHelperRequestSource),
243             DECLARE_NAPI_FUNCTION("commitEditedAsset", PhotoAccessHelperCommitEditedAsset),
244             DECLARE_NAPI_FUNCTION("revertToOriginal", PhotoAccessHelperRevertToOriginal),
245             DECLARE_NAPI_FUNCTION("getAnalysisData", PhotoAccessHelperGetAnalysisData),
246             DECLARE_NAPI_FUNCTION("getEditData", PhotoAccessHelperGetEditData),
247         }
248     };
249     MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
250     return exports;
251 }
252 
DetachFileAssetFunc(napi_env env,void * value,void *)253 inline void *DetachFileAssetFunc(napi_env env, void *value, void *)
254 {
255     if (value == nullptr) {
256         NAPI_ERR_LOG("detach value is null");
257         return nullptr;
258     }
259     auto fileAssetNapi = reinterpret_cast<FileAssetNapi*>(value);
260     std::shared_ptr<FileAsset> detachFileAsset = fileAssetNapi->GetFileAssetInstance();
261     TransferFileAsset *transferFileAsset = new TransferFileAsset();
262     return transferFileAsset;
263 }
264 
AttachFileAssetFunc(napi_env env,void * value,void *)265 napi_value AttachFileAssetFunc(napi_env env, void *value, void *)
266 {
267     if (value == nullptr) {
268         NAPI_ERR_LOG("attach value is null");
269         return nullptr;
270     }
271     auto transferFileAsset = reinterpret_cast<TransferFileAsset*>(value);
272     std::shared_ptr<FileAsset> fileAsset = std::move(transferFileAsset->fileAsset);
273     delete transferFileAsset;
274     NAPI_ASSERT(env, fileAsset != nullptr, "AttachFileAssetFunc fileAsset is null");
275     napi_value result = FileAssetNapi::AttachCreateFileAsset(env, fileAsset);
276     NAPI_ASSERT(env, result != nullptr, "AttachFileAssetFunc result is null");
277     return result;
278 }
279 
280 // Constructor callback
FileAssetNapiConstructor(napi_env env,napi_callback_info info)281 napi_value FileAssetNapi::FileAssetNapiConstructor(napi_env env, napi_callback_info info)
282 {
283     napi_status status;
284     napi_value result = nullptr;
285     napi_value thisVar = nullptr;
286 
287     napi_get_undefined(env, &result);
288     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
289     if (status == napi_ok && thisVar != nullptr) {
290         std::unique_ptr<FileAssetNapi> obj = std::make_unique<FileAssetNapi>();
291         if (obj != nullptr) {
292             obj->env_ = env;
293             if (sFileAsset_ != nullptr) {
294                 obj->UpdateFileAssetInfo();
295             }
296             napi_coerce_to_native_binding_object(
297                 env, thisVar, DetachFileAssetFunc, AttachFileAssetFunc, obj.get(), nullptr);
298             status = napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()),
299                                FileAssetNapi::FileAssetNapiDestructor, nullptr, nullptr);
300             if (status == napi_ok) {
301                 obj.release();
302                 return thisVar;
303             } else {
304                 NAPI_ERR_LOG("Failure wrapping js to native napi, status: %{public}d", status);
305             }
306         }
307     }
308 
309     return result;
310 }
311 
AttachCreateFileAsset(napi_env env,std::shared_ptr<FileAsset> & iAsset)312 napi_value FileAssetNapi::AttachCreateFileAsset(napi_env env, std::shared_ptr<FileAsset> &iAsset)
313 {
314     if (iAsset == nullptr) {
315         return nullptr;
316     }
317     napi_value constructor = nullptr;
318     napi_ref constructorRef = nullptr;
319     napi_value exports = nullptr;
320     if (iAsset->GetResultNapiType() == ResultNapiType::TYPE_USERFILE_MGR) {
321         if (userFileMgrConstructor_ == nullptr) {
322             NAPI_INFO_LOG("AttachCreateFileAsset userFileMgrConstructor_ is null");
323             napi_create_object(env, &exports);
324             FileAssetNapi::UserFileMgrInit(env, exports);
325         }
326         constructorRef = userFileMgrConstructor_;
327     } else if (iAsset->GetResultNapiType() == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
328         if (photoAccessHelperConstructor_ == nullptr) {
329             NAPI_INFO_LOG("AttachCreateFileAsset photoAccessHelperConstructor_ is null");
330             napi_create_object(env, &exports);
331             FileAssetNapi::PhotoAccessHelperInit(env, exports);
332         }
333         constructorRef = photoAccessHelperConstructor_;
334     }
335     if (constructorRef == nullptr) {
336         NAPI_ASSERT(env, false, "AttachCreateFileAsset constructorRef is null");
337     }
338     napi_status status = napi_get_reference_value(env, constructorRef, &constructor);
339     NAPI_ASSERT(env, status == napi_ok, "AttachCreateFileAsset napi_get_reference_value failed");
340     sFileAsset_ = iAsset;
341     napi_value result = nullptr;
342     status = napi_new_instance(env, constructor, 0, nullptr, &result);
343     NAPI_ASSERT(env, status == napi_ok, "AttachCreateFileAsset napi_new_instance failed");
344     sFileAsset_ = nullptr;
345     return result;
346 }
347 
348 
CreateFileAsset(napi_env env,unique_ptr<FileAsset> & iAsset)349 napi_value FileAssetNapi::CreateFileAsset(napi_env env, unique_ptr<FileAsset> &iAsset)
350 {
351     if (iAsset == nullptr) {
352         return nullptr;
353     }
354 
355     napi_value constructor = nullptr;
356     napi_ref constructorRef;
357     if (iAsset->GetResultNapiType() == ResultNapiType::TYPE_USERFILE_MGR) {
358         constructorRef = userFileMgrConstructor_;
359     } else if (iAsset->GetResultNapiType() == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
360         constructorRef = photoAccessHelperConstructor_;
361     } else {
362         constructorRef = sConstructor_;
363     }
364 
365     NAPI_CALL(env, napi_get_reference_value(env, constructorRef, &constructor));
366 
367     sFileAsset_ = std::move(iAsset);
368 
369     napi_value result = nullptr;
370     NAPI_CALL(env, napi_new_instance(env, constructor, 0, nullptr, &result));
371 
372     sFileAsset_ = nullptr;
373     return result;
374 }
375 
CreatePhotoAsset(napi_env env,shared_ptr<FileAsset> & fileAsset)376 napi_value FileAssetNapi::CreatePhotoAsset(napi_env env, shared_ptr<FileAsset> &fileAsset)
377 {
378     if (fileAsset == nullptr || fileAsset->GetResultNapiType() != ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
379         NAPI_ERR_LOG("Unsupported fileAsset");
380         return nullptr;
381     }
382 
383     napi_value constructor = nullptr;
384     napi_value result = nullptr;
385     NAPI_CALL(env, napi_get_reference_value(env, photoAccessHelperConstructor_, &constructor));
386     NAPI_CALL(env, napi_new_instance(env, constructor, 0, nullptr, &result));
387     CHECK_COND(env, result != nullptr, JS_INNER_FAIL);
388 
389     FileAssetNapi* fileAssetNapi = nullptr;
390     CHECK_ARGS(env, napi_unwrap(env, result, reinterpret_cast<void**>(&fileAssetNapi)), JS_INNER_FAIL);
391     CHECK_COND(env, fileAssetNapi != nullptr, JS_INNER_FAIL);
392     fileAssetNapi->fileAssetPtr = fileAsset;
393     return result;
394 }
395 
GetFileDisplayName() const396 std::string FileAssetNapi::GetFileDisplayName() const
397 {
398     return fileAssetPtr->GetDisplayName();
399 }
400 
GetRelativePath() const401 std::string FileAssetNapi::GetRelativePath() const
402 {
403     return fileAssetPtr->GetRelativePath();
404 }
405 
GetFilePath() const406 std::string FileAssetNapi::GetFilePath() const
407 {
408     return fileAssetPtr->GetPath();
409 }
410 
GetTitle() const411 std::string FileAssetNapi::GetTitle() const
412 {
413     return fileAssetPtr->GetTitle();
414 }
415 
GetFileUri() const416 std::string FileAssetNapi::GetFileUri() const
417 {
418     return fileAssetPtr->GetUri();
419 }
420 
GetFileId() const421 int32_t FileAssetNapi::GetFileId() const
422 {
423     return fileAssetPtr->GetId();
424 }
425 
GetMediaType() const426 Media::MediaType FileAssetNapi::GetMediaType() const
427 {
428     return fileAssetPtr->GetMediaType();
429 }
430 
GetOrientation() const431 int32_t FileAssetNapi::GetOrientation() const
432 {
433     return fileAssetPtr->GetOrientation();
434 }
435 
GetNetworkId() const436 std::string FileAssetNapi::GetNetworkId() const
437 {
438     return MediaFileUtils::GetNetworkIdFromUri(GetFileUri());
439 }
440 
IsFavorite() const441 bool FileAssetNapi::IsFavorite() const
442 {
443     return fileAssetPtr->IsFavorite();
444 }
445 
SetFavorite(bool isFavorite)446 void FileAssetNapi::SetFavorite(bool isFavorite)
447 {
448     fileAssetPtr->SetFavorite(isFavorite);
449 }
450 
IsTrash() const451 bool FileAssetNapi::IsTrash() const
452 {
453     return (fileAssetPtr->GetIsTrash() != NOT_TRASH);
454 }
455 
SetTrash(bool isTrash)456 void FileAssetNapi::SetTrash(bool isTrash)
457 {
458     int32_t trashFlag = (isTrash ? IS_TRASH : NOT_TRASH);
459     fileAssetPtr->SetIsTrash(trashFlag);
460 }
461 
IsHidden() const462 bool FileAssetNapi::IsHidden() const
463 {
464     return fileAssetPtr->IsHidden();
465 }
466 
SetHidden(bool isHidden)467 void FileAssetNapi::SetHidden(bool isHidden)
468 {
469     fileAssetPtr->SetHidden(isHidden);
470 }
471 
GetAllExif() const472 std::string FileAssetNapi::GetAllExif() const
473 {
474     return fileAssetPtr->GetAllExif();
475 }
476 
GetUserComment() const477 std::string FileAssetNapi::GetUserComment() const
478 {
479     return fileAssetPtr->GetUserComment();
480 }
481 
GetNapiObject(napi_env env,napi_callback_info info,FileAssetNapi ** obj)482 napi_status GetNapiObject(napi_env env, napi_callback_info info, FileAssetNapi **obj)
483 {
484     napi_value thisVar = nullptr;
485     CHECK_STATUS_RET(napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr), "Failed to get cb info");
486     CHECK_STATUS_RET(napi_unwrap(env, thisVar, reinterpret_cast<void **>(obj)), "Failed to unwrap thisVar");
487     CHECK_COND_RET(*obj != nullptr, napi_invalid_arg, "Failed to get napi object!");
488     return napi_ok;
489 }
490 
JSGetFileId(napi_env env,napi_callback_info info)491 napi_value FileAssetNapi::JSGetFileId(napi_env env, napi_callback_info info)
492 {
493     napi_status status;
494     napi_value jsResult = nullptr;
495     FileAssetNapi *obj = nullptr;
496     int32_t id;
497     napi_value thisVar = nullptr;
498 
499     napi_get_undefined(env, &jsResult);
500     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
501     if (status != napi_ok || thisVar == nullptr) {
502         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
503         return jsResult;
504     }
505 
506     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
507     if (status == napi_ok && obj != nullptr) {
508         id = obj->GetFileId();
509 #ifdef MEDIALIBRARY_COMPATIBILITY
510         int64_t virtualId = 0;
511         if (MediaFileUtils::IsFileTablePath(obj->GetFilePath())) {
512             virtualId = MediaFileUtils::GetVirtualIdByType(id, MediaType::MEDIA_TYPE_FILE);
513         } else {
514             virtualId = MediaFileUtils::GetVirtualIdByType(id, obj->GetMediaType());
515         }
516         napi_create_int64(env, virtualId, &jsResult);
517 #else
518         napi_create_int32(env, id, &jsResult);
519 #endif
520     }
521 
522     return jsResult;
523 }
524 
JSGetFileUri(napi_env env,napi_callback_info info)525 napi_value FileAssetNapi::JSGetFileUri(napi_env env, napi_callback_info info)
526 {
527     FileAssetNapi *obj = nullptr;
528     CHECK_ARGS(env, GetNapiObject(env, info, &obj), JS_INNER_FAIL);
529 
530     napi_value jsResult = nullptr;
531     CHECK_ARGS(env, napi_create_string_utf8(env, obj->GetFileUri().c_str(), NAPI_AUTO_LENGTH, &jsResult),
532         JS_INNER_FAIL);
533     return jsResult;
534 }
535 
JSGetFilePath(napi_env env,napi_callback_info info)536 napi_value FileAssetNapi::JSGetFilePath(napi_env env, napi_callback_info info)
537 {
538     napi_status status;
539     napi_value jsResult = nullptr;
540     FileAssetNapi *obj = nullptr;
541     string path = "";
542     napi_value thisVar = nullptr;
543 
544     napi_get_undefined(env, &jsResult);
545     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
546     if (status != napi_ok || thisVar == nullptr) {
547         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
548         return jsResult;
549     }
550 
551     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
552     if (status == napi_ok && obj != nullptr) {
553         path = obj->GetFilePath();
554         napi_create_string_utf8(env, path.c_str(), NAPI_AUTO_LENGTH, &jsResult);
555     }
556 
557     return jsResult;
558 }
559 
JSGetFileDisplayName(napi_env env,napi_callback_info info)560 napi_value FileAssetNapi::JSGetFileDisplayName(napi_env env, napi_callback_info info)
561 {
562     napi_status status;
563     napi_value jsResult = nullptr;
564     FileAssetNapi *obj = nullptr;
565     string displayName = "";
566     napi_value thisVar = nullptr;
567 
568     napi_get_undefined(env, &jsResult);
569     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
570     if (status != napi_ok || thisVar == nullptr) {
571         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
572         return jsResult;
573     }
574 
575     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
576     if (status == napi_ok && obj != nullptr) {
577         displayName = obj->GetFileDisplayName();
578         napi_create_string_utf8(env, displayName.c_str(), NAPI_AUTO_LENGTH, &jsResult);
579     }
580 
581     return jsResult;
582 }
583 
JSSetFileDisplayName(napi_env env,napi_callback_info info)584 napi_value FileAssetNapi::JSSetFileDisplayName(napi_env env, napi_callback_info info)
585 {
586     napi_status status;
587     napi_value undefinedResult = nullptr;
588     FileAssetNapi *obj = nullptr;
589     napi_valuetype valueType = napi_undefined;
590     size_t res = 0;
591     char buffer[FILENAME_MAX];
592     size_t argc = ARGS_ONE;
593     napi_value argv[ARGS_ONE] = {0};
594     napi_value thisVar = nullptr;
595 
596     napi_get_undefined(env, &undefinedResult);
597 
598     GET_JS_ARGS(env, info, argc, argv, thisVar);
599     NAPI_ASSERT(env, argc == ARGS_ONE, "requires 1 parameter");
600 
601     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
602     if (status == napi_ok && obj != nullptr) {
603         if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string) {
604             NAPI_ERR_LOG("Invalid arguments type! valueType: %{public}d", valueType);
605             return undefinedResult;
606         }
607         status = napi_get_value_string_utf8(env, argv[PARAM0], buffer, FILENAME_MAX, &res);
608         if (status == napi_ok) {
609             string displayName = string(buffer);
610             obj->fileAssetPtr->SetDisplayName(displayName);
611 #ifdef MEDIALIBRARY_COMPATIBILITY
612             obj->fileAssetPtr->SetTitle(MediaFileUtils::GetTitleFromDisplayName(displayName));
613 #endif
614         }
615     }
616 
617     return undefinedResult;
618 }
619 
JSGetMimeType(napi_env env,napi_callback_info info)620 napi_value FileAssetNapi::JSGetMimeType(napi_env env, napi_callback_info info)
621 {
622     napi_status status;
623     napi_value jsResult = nullptr;
624     FileAssetNapi *obj = nullptr;
625     string mimeType = "";
626     napi_value thisVar = nullptr;
627 
628     napi_get_undefined(env, &jsResult);
629     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
630     if (status != napi_ok || thisVar == nullptr) {
631         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
632         return jsResult;
633     }
634 
635     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
636     if (status == napi_ok && obj != nullptr) {
637         mimeType = obj->fileAssetPtr->GetMimeType();
638         napi_create_string_utf8(env, mimeType.c_str(), NAPI_AUTO_LENGTH, &jsResult);
639     }
640 
641     return jsResult;
642 }
643 
JSGetMediaType(napi_env env,napi_callback_info info)644 napi_value FileAssetNapi::JSGetMediaType(napi_env env, napi_callback_info info)
645 {
646     napi_status status;
647     napi_value jsResult = nullptr;
648     FileAssetNapi *obj = nullptr;
649     int32_t mediaType;
650     napi_value thisVar = nullptr;
651 
652     napi_get_undefined(env, &jsResult);
653     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
654     if (status != napi_ok || thisVar == nullptr) {
655         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
656         return jsResult;
657     }
658 
659     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
660     if (status == napi_ok && obj != nullptr) {
661         mediaType = static_cast<int32_t>(obj->GetMediaType());
662         napi_create_int32(env, mediaType, &jsResult);
663     }
664 
665     return jsResult;
666 }
667 
JSGetTitle(napi_env env,napi_callback_info info)668 napi_value FileAssetNapi::JSGetTitle(napi_env env, napi_callback_info info)
669 {
670     napi_status status;
671     napi_value jsResult = nullptr;
672     FileAssetNapi *obj = nullptr;
673     string title = "";
674     napi_value thisVar = nullptr;
675 
676     napi_get_undefined(env, &jsResult);
677     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
678     if (status != napi_ok || thisVar == nullptr) {
679         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
680         return jsResult;
681     }
682 
683     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
684     if (status == napi_ok && obj != nullptr) {
685         title = obj->GetTitle();
686         napi_create_string_utf8(env, title.c_str(), NAPI_AUTO_LENGTH, &jsResult);
687     }
688 
689     return jsResult;
690 }
JSSetTitle(napi_env env,napi_callback_info info)691 napi_value FileAssetNapi::JSSetTitle(napi_env env, napi_callback_info info)
692 {
693     napi_status status;
694     napi_value undefinedResult = nullptr;
695     FileAssetNapi *obj = nullptr;
696     napi_valuetype valueType = napi_undefined;
697     size_t res = 0;
698     char buffer[FILENAME_MAX];
699     size_t argc = ARGS_ONE;
700     napi_value argv[ARGS_ONE] = {0};
701     napi_value thisVar = nullptr;
702     napi_get_undefined(env, &undefinedResult);
703     GET_JS_ARGS(env, info, argc, argv, thisVar);
704     NAPI_ASSERT(env, argc == ARGS_ONE, "requires 1 parameter");
705     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
706     if (status == napi_ok && obj != nullptr) {
707         if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string) {
708             NAPI_ERR_LOG("Invalid arguments type! valueType: %{public}d", valueType);
709             return undefinedResult;
710         }
711         status = napi_get_value_string_utf8(env, argv[PARAM0], buffer, FILENAME_MAX, &res);
712         if (status == napi_ok) {
713             string title = string(buffer);
714             obj->fileAssetPtr->SetTitle(title);
715 #ifdef MEDIALIBRARY_COMPATIBILITY
716             string oldDisplayName = obj->fileAssetPtr->GetDisplayName();
717             string ext = MediaFileUtils::SplitByChar(oldDisplayName, '.');
718             string newDisplayName = title + "." + ext;
719             obj->fileAssetPtr->SetDisplayName(newDisplayName);
720 #endif
721         }
722     }
723     return undefinedResult;
724 }
725 
JSGetSize(napi_env env,napi_callback_info info)726 napi_value FileAssetNapi::JSGetSize(napi_env env, napi_callback_info info)
727 {
728     napi_status status;
729     napi_value jsResult = nullptr;
730     FileAssetNapi *obj = nullptr;
731     int64_t size;
732     napi_value thisVar = nullptr;
733 
734     napi_get_undefined(env, &jsResult);
735     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
736     if (status != napi_ok || thisVar == nullptr) {
737         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
738         return jsResult;
739     }
740 
741     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
742     if (status == napi_ok && obj != nullptr) {
743         size = obj->fileAssetPtr->GetSize();
744         napi_create_int64(env, size, &jsResult);
745     }
746 
747     return jsResult;
748 }
749 
JSGetAlbumId(napi_env env,napi_callback_info info)750 napi_value FileAssetNapi::JSGetAlbumId(napi_env env, napi_callback_info info)
751 {
752     napi_status status;
753     napi_value jsResult = nullptr;
754     FileAssetNapi *obj = nullptr;
755     int32_t albumId;
756     napi_value thisVar = nullptr;
757 
758     napi_get_undefined(env, &jsResult);
759     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
760     if (status != napi_ok || thisVar == nullptr) {
761         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
762         return jsResult;
763     }
764 
765     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
766     if (status == napi_ok && obj != nullptr) {
767         albumId = obj->fileAssetPtr->GetAlbumId();
768         napi_create_int32(env, albumId, &jsResult);
769     }
770 
771     return jsResult;
772 }
773 
JSGetAlbumName(napi_env env,napi_callback_info info)774 napi_value FileAssetNapi::JSGetAlbumName(napi_env env, napi_callback_info info)
775 {
776     napi_status status;
777     napi_value jsResult = nullptr;
778     FileAssetNapi *obj = nullptr;
779     string albumName = "";
780     napi_value thisVar = nullptr;
781 
782     napi_get_undefined(env, &jsResult);
783     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
784     if (status != napi_ok || thisVar == nullptr) {
785         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
786         return jsResult;
787     }
788 
789     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
790     if (status == napi_ok && obj != nullptr) {
791         albumName = obj->fileAssetPtr->GetAlbumName();
792         napi_create_string_utf8(env, albumName.c_str(), NAPI_AUTO_LENGTH, &jsResult);
793     }
794 
795     return jsResult;
796 }
797 
JSGetCount(napi_env env,napi_callback_info info)798 napi_value FileAssetNapi::JSGetCount(napi_env env, napi_callback_info info)
799 {
800     napi_status status;
801     napi_value jsResult = nullptr;
802     napi_value thisVar = nullptr;
803 
804     napi_get_undefined(env, &jsResult);
805     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
806     if ((status != napi_ok) || (thisVar == nullptr)) {
807         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
808         return jsResult;
809     }
810 
811     FileAssetNapi *obj = nullptr;
812     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
813     if ((status == napi_ok) && (obj != nullptr)) {
814         napi_create_int32(env, obj->fileAssetPtr->GetCount(), &jsResult);
815     }
816 
817     return jsResult;
818 }
819 
JSGetDateAdded(napi_env env,napi_callback_info info)820 napi_value FileAssetNapi::JSGetDateAdded(napi_env env, napi_callback_info info)
821 {
822     napi_status status;
823     napi_value jsResult = nullptr;
824     FileAssetNapi *obj = nullptr;
825     int64_t dateAdded;
826     napi_value thisVar = nullptr;
827 
828     napi_get_undefined(env, &jsResult);
829     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
830     if (status != napi_ok || thisVar == nullptr) {
831         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
832         return jsResult;
833     }
834 
835     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
836     if (status == napi_ok && obj != nullptr) {
837         dateAdded = obj->fileAssetPtr->GetDateAdded() / MSEC_TO_SEC;
838         napi_create_int64(env, dateAdded, &jsResult);
839     }
840 
841     return jsResult;
842 }
843 
JSGetDateTrashed(napi_env env,napi_callback_info info)844 napi_value FileAssetNapi::JSGetDateTrashed(napi_env env, napi_callback_info info)
845 {
846     napi_status status;
847     napi_value jsResult = nullptr;
848     FileAssetNapi *obj = nullptr;
849     int64_t dateTrashed;
850     napi_value thisVar = nullptr;
851 
852     napi_get_undefined(env, &jsResult);
853     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
854     if (status != napi_ok || thisVar == nullptr) {
855         NAPI_ERR_LOG("Invalid arguments! status: %{private}d", status);
856         return jsResult;
857     }
858 
859     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
860     if (status == napi_ok && obj != nullptr) {
861         dateTrashed = obj->fileAssetPtr->GetDateTrashed() / MSEC_TO_SEC;
862         napi_create_int64(env, dateTrashed, &jsResult);
863     }
864 
865     return jsResult;
866 }
867 
JSGetDateModified(napi_env env,napi_callback_info info)868 napi_value FileAssetNapi::JSGetDateModified(napi_env env, napi_callback_info info)
869 {
870     napi_status status;
871     napi_value jsResult = nullptr;
872     FileAssetNapi *obj = nullptr;
873     int64_t dateModified;
874     napi_value thisVar = nullptr;
875 
876     napi_get_undefined(env, &jsResult);
877     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
878     if (status != napi_ok || thisVar == nullptr) {
879         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
880         return jsResult;
881     }
882 
883     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
884     if (status == napi_ok && obj != nullptr) {
885         dateModified = obj->fileAssetPtr->GetDateModified() / MSEC_TO_SEC;
886         napi_create_int64(env, dateModified, &jsResult);
887     }
888 
889     return jsResult;
890 }
891 
JSGetOrientation(napi_env env,napi_callback_info info)892 napi_value FileAssetNapi::JSGetOrientation(napi_env env, napi_callback_info info)
893 {
894     napi_status status;
895     napi_value jsResult = nullptr;
896     FileAssetNapi *obj = nullptr;
897     int32_t orientation;
898     napi_value thisVar = nullptr;
899 
900     napi_get_undefined(env, &jsResult);
901     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
902     if (status != napi_ok || thisVar == nullptr) {
903         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
904         return jsResult;
905     }
906 
907     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
908     if (status == napi_ok && obj != nullptr) {
909         orientation = obj->GetOrientation();
910         napi_create_int32(env, orientation, &jsResult);
911     }
912 
913     return jsResult;
914 }
JSSetOrientation(napi_env env,napi_callback_info info)915 napi_value FileAssetNapi::JSSetOrientation(napi_env env, napi_callback_info info)
916 {
917     napi_status status;
918     napi_value undefinedResult = nullptr;
919     FileAssetNapi *obj = nullptr;
920     napi_valuetype valueType = napi_undefined;
921     int32_t orientation;
922     size_t argc = ARGS_ONE;
923     napi_value argv[ARGS_ONE] = {0};
924     napi_value thisVar = nullptr;
925     napi_get_undefined(env, &undefinedResult);
926 
927     GET_JS_ARGS(env, info, argc, argv, thisVar);
928     NAPI_ASSERT(env, argc == ARGS_ONE, "requires 1 parameter");
929 
930     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
931     if (status == napi_ok && obj != nullptr) {
932         if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_number) {
933             NAPI_ERR_LOG("Invalid arguments type! valueType: %{public}d", valueType);
934             return undefinedResult;
935         }
936 
937         status = napi_get_value_int32(env, argv[PARAM0], &orientation);
938         if (status == napi_ok) {
939             obj->fileAssetPtr->SetOrientation(orientation);
940         }
941     }
942 
943     return undefinedResult;
944 }
945 
JSGetWidth(napi_env env,napi_callback_info info)946 napi_value FileAssetNapi::JSGetWidth(napi_env env, napi_callback_info info)
947 {
948     napi_status status;
949     napi_value jsResult = nullptr;
950     FileAssetNapi *obj = nullptr;
951     int32_t width;
952     napi_value thisVar = nullptr;
953 
954     napi_get_undefined(env, &jsResult);
955     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
956     if (status != napi_ok || thisVar == nullptr) {
957         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
958         return jsResult;
959     }
960 
961     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
962     if (status == napi_ok && obj != nullptr) {
963         width = obj->fileAssetPtr->GetWidth();
964         napi_create_int32(env, width, &jsResult);
965     }
966 
967     return jsResult;
968 }
969 
JSGetHeight(napi_env env,napi_callback_info info)970 napi_value FileAssetNapi::JSGetHeight(napi_env env, napi_callback_info info)
971 {
972     napi_status status;
973     napi_value jsResult = nullptr;
974     FileAssetNapi *obj = nullptr;
975     int32_t height;
976     napi_value thisVar = nullptr;
977 
978     napi_get_undefined(env, &jsResult);
979     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
980     if (status != napi_ok || thisVar == nullptr) {
981         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
982         return jsResult;
983     }
984 
985     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
986     if (status == napi_ok && obj != nullptr) {
987         height = obj->fileAssetPtr->GetHeight();
988         napi_create_int32(env, height, &jsResult);
989     }
990 
991     return jsResult;
992 }
993 
JSGetRelativePath(napi_env env,napi_callback_info info)994 napi_value FileAssetNapi::JSGetRelativePath(napi_env env, napi_callback_info info)
995 {
996     napi_status status;
997     napi_value jsResult = nullptr;
998     FileAssetNapi *obj = nullptr;
999     string relativePath = "";
1000     napi_value thisVar = nullptr;
1001 
1002     napi_get_undefined(env, &jsResult);
1003     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
1004     if (status != napi_ok || thisVar == nullptr) {
1005         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
1006         return jsResult;
1007     }
1008 
1009     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1010     if (status == napi_ok && obj != nullptr) {
1011         relativePath = obj->GetRelativePath();
1012         napi_create_string_utf8(env, relativePath.c_str(), NAPI_AUTO_LENGTH, &jsResult);
1013     }
1014 
1015     return jsResult;
1016 }
1017 
JSSetRelativePath(napi_env env,napi_callback_info info)1018 napi_value FileAssetNapi::JSSetRelativePath(napi_env env, napi_callback_info info)
1019 {
1020     napi_status status;
1021     napi_value undefinedResult = nullptr;
1022     FileAssetNapi *obj = nullptr;
1023     napi_valuetype valueType = napi_undefined;
1024     size_t res = 0;
1025     char buffer[ARG_BUF_SIZE];
1026     size_t argc = ARGS_ONE;
1027     napi_value argv[ARGS_ONE] = {0};
1028     napi_value thisVar = nullptr;
1029     napi_get_undefined(env, &undefinedResult);
1030     GET_JS_ARGS(env, info, argc, argv, thisVar);
1031     NAPI_ASSERT(env, argc == ARGS_ONE, "requires 1 parameter");
1032     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1033     if (status == napi_ok && obj != nullptr) {
1034         if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string) {
1035             NAPI_ERR_LOG("Invalid arguments type! valueType: %{public}d", valueType);
1036             return undefinedResult;
1037         }
1038         status = napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res);
1039         if (status == napi_ok) {
1040             obj->fileAssetPtr->SetRelativePath(string(buffer));
1041         }
1042     }
1043     return undefinedResult;
1044 }
JSGetAlbum(napi_env env,napi_callback_info info)1045 napi_value FileAssetNapi::JSGetAlbum(napi_env env, napi_callback_info info)
1046 {
1047     napi_status status;
1048     napi_value jsResult = nullptr;
1049     FileAssetNapi *obj = nullptr;
1050     string album = "";
1051     napi_value thisVar = nullptr;
1052 
1053     napi_get_undefined(env, &jsResult);
1054     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
1055     if (status != napi_ok || thisVar == nullptr) {
1056         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
1057         return jsResult;
1058     }
1059 
1060     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1061     if (status == napi_ok && obj != nullptr) {
1062         album = obj->fileAssetPtr->GetAlbum();
1063         napi_create_string_utf8(env, album.c_str(), NAPI_AUTO_LENGTH, &jsResult);
1064     }
1065 
1066     return jsResult;
1067 }
1068 
JSGetArtist(napi_env env,napi_callback_info info)1069 napi_value FileAssetNapi::JSGetArtist(napi_env env, napi_callback_info info)
1070 {
1071     napi_status status;
1072     napi_value jsResult = nullptr;
1073     FileAssetNapi *obj = nullptr;
1074     string artist = "";
1075     napi_value thisVar = nullptr;
1076 
1077     napi_get_undefined(env, &jsResult);
1078     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
1079     if (status != napi_ok || thisVar == nullptr) {
1080         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
1081         return jsResult;
1082     }
1083 
1084     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1085     if (status == napi_ok && obj != nullptr) {
1086         artist = obj->fileAssetPtr->GetArtist();
1087         napi_create_string_utf8(env, artist.c_str(), NAPI_AUTO_LENGTH, &jsResult);
1088     }
1089 
1090     return jsResult;
1091 }
1092 
JSGetDuration(napi_env env,napi_callback_info info)1093 napi_value FileAssetNapi::JSGetDuration(napi_env env, napi_callback_info info)
1094 {
1095     napi_status status;
1096     napi_value jsResult = nullptr;
1097     FileAssetNapi *obj = nullptr;
1098     int32_t duration;
1099     napi_value thisVar = nullptr;
1100 
1101     napi_get_undefined(env, &jsResult);
1102     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
1103     if (status != napi_ok || thisVar == nullptr) {
1104         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
1105         return jsResult;
1106     }
1107 
1108     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1109     if (status == napi_ok && obj != nullptr) {
1110         duration = obj->fileAssetPtr->GetDuration();
1111         napi_create_int32(env, duration, &jsResult);
1112     }
1113 
1114     return jsResult;
1115 }
1116 
JSParent(napi_env env,napi_callback_info info)1117 napi_value FileAssetNapi::JSParent(napi_env env, napi_callback_info info)
1118 {
1119     napi_status status;
1120     napi_value jsResult = nullptr;
1121     FileAssetNapi *obj = nullptr;
1122     int32_t parent;
1123     napi_value thisVar = nullptr;
1124     napi_get_undefined(env, &jsResult);
1125     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
1126     if (status != napi_ok || thisVar == nullptr) {
1127         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
1128         return jsResult;
1129     }
1130     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1131     if (status == napi_ok && obj != nullptr) {
1132         parent = obj->fileAssetPtr->GetParent();
1133         napi_create_int32(env, parent, &jsResult);
1134     }
1135     return jsResult;
1136 }
JSGetAlbumUri(napi_env env,napi_callback_info info)1137 napi_value FileAssetNapi::JSGetAlbumUri(napi_env env, napi_callback_info info)
1138 {
1139     napi_status status;
1140     napi_value jsResult = nullptr;
1141     FileAssetNapi *obj = nullptr;
1142     string albumUri = "";
1143     napi_value thisVar = nullptr;
1144     napi_get_undefined(env, &jsResult);
1145     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
1146     if (status != napi_ok || thisVar == nullptr) {
1147         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
1148         return jsResult;
1149     }
1150     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1151     if (status == napi_ok && obj != nullptr) {
1152         albumUri = obj->fileAssetPtr->GetAlbumUri();
1153         napi_create_string_utf8(env, albumUri.c_str(), NAPI_AUTO_LENGTH, &jsResult);
1154     }
1155     return jsResult;
1156 }
JSGetDateTaken(napi_env env,napi_callback_info info)1157 napi_value FileAssetNapi::JSGetDateTaken(napi_env env, napi_callback_info info)
1158 {
1159     napi_status status;
1160     napi_value jsResult = nullptr;
1161     FileAssetNapi *obj = nullptr;
1162     int64_t dateTaken;
1163     napi_value thisVar = nullptr;
1164     napi_get_undefined(env, &jsResult);
1165     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
1166     if (status != napi_ok || thisVar == nullptr) {
1167         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
1168         return jsResult;
1169     }
1170     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1171     if (status == napi_ok && obj != nullptr) {
1172         dateTaken = obj->fileAssetPtr->GetDateTaken();
1173         napi_create_int64(env, dateTaken, &jsResult);
1174     }
1175     return jsResult;
1176 }
1177 
BuildCommitModifyValuesBucket(FileAssetAsyncContext * context,DataShareValuesBucket & valuesBucket)1178 void BuildCommitModifyValuesBucket(FileAssetAsyncContext* context, DataShareValuesBucket &valuesBucket)
1179 {
1180     const auto fileAsset = context->objectPtr;
1181     if (context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
1182         valuesBucket.Put(MediaColumn::MEDIA_TITLE, fileAsset->GetTitle());
1183     } else if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
1184         valuesBucket.Put(MediaColumn::MEDIA_NAME, fileAsset->GetDisplayName());
1185     } else {
1186 #ifdef MEDIALIBRARY_COMPATIBILITY
1187         valuesBucket.Put(MEDIA_DATA_DB_TITLE, fileAsset->GetTitle());
1188         valuesBucket.Put(MEDIA_DATA_DB_RELATIVE_PATH,
1189             MediaFileUtils::AddDocsToRelativePath(fileAsset->GetRelativePath()));
1190         if (fileAsset->GetMediaType() != MediaType::MEDIA_TYPE_AUDIO) {
1191             // IMAGE, VIDEO AND FILES
1192             if (fileAsset->GetOrientation() >= 0) {
1193                 valuesBucket.Put(MEDIA_DATA_DB_ORIENTATION, fileAsset->GetOrientation());
1194             }
1195             if ((fileAsset->GetMediaType() != MediaType::MEDIA_TYPE_IMAGE) &&
1196                 (fileAsset->GetMediaType() != MediaType::MEDIA_TYPE_VIDEO)) {
1197                 // ONLY FILES
1198                 valuesBucket.Put(MEDIA_DATA_DB_URI, fileAsset->GetUri());
1199                 valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, fileAsset->GetMediaType());
1200             }
1201         }
1202 #else
1203         valuesBucket.Put(MEDIA_DATA_DB_URI, fileAsset->GetUri());
1204         valuesBucket.Put(MEDIA_DATA_DB_TITLE, fileAsset->GetTitle());
1205 
1206         if (fileAsset->GetOrientation() >= 0) {
1207             valuesBucket.Put(MEDIA_DATA_DB_ORIENTATION, fileAsset->GetOrientation());
1208         }
1209         valuesBucket.Put(MEDIA_DATA_DB_RELATIVE_PATH, fileAsset->GetRelativePath());
1210         valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, fileAsset->GetMediaType());
1211 #endif
1212         valuesBucket.Put(MEDIA_DATA_DB_NAME, fileAsset->GetDisplayName());
1213     }
1214 }
1215 
1216 #ifdef MEDIALIBRARY_COMPATIBILITY
BuildCommitModifyUriApi9(FileAssetAsyncContext * context,string & uri)1217 static void BuildCommitModifyUriApi9(FileAssetAsyncContext *context, string &uri)
1218 {
1219     if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
1220         context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
1221         uri = URI_UPDATE_PHOTO;
1222     } else if (context->objectPtr->GetMediaType() == MEDIA_TYPE_AUDIO) {
1223         uri = URI_UPDATE_AUDIO;
1224     } else if (context->objectPtr->GetMediaType() == MEDIA_TYPE_FILE) {
1225         uri = URI_UPDATE_FILE;
1226     }
1227 }
1228 #endif
1229 
BuildCommitModifyUriApi10(FileAssetAsyncContext * context,string & uri)1230 static void BuildCommitModifyUriApi10(FileAssetAsyncContext *context, string &uri)
1231 {
1232     if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
1233         context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
1234         uri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ? UFM_UPDATE_PHOTO : PAH_UPDATE_PHOTO;
1235     } else if (context->objectPtr->GetMediaType() == MEDIA_TYPE_AUDIO) {
1236         uri = UFM_UPDATE_AUDIO;
1237     }
1238 }
1239 
CheckDisplayNameInCommitModify(FileAssetAsyncContext * context)1240 static bool CheckDisplayNameInCommitModify(FileAssetAsyncContext *context)
1241 {
1242     if (context->resultNapiType != ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
1243         if (context->objectPtr->GetMediaType() != MediaType::MEDIA_TYPE_FILE) {
1244             if (MediaFileUtils::CheckDisplayName(context->objectPtr->GetDisplayName()) != E_OK) {
1245                 context->error = JS_E_DISPLAYNAME;
1246                 return false;
1247             }
1248         } else {
1249             if (MediaFileUtils::CheckFileDisplayName(context->objectPtr->GetDisplayName()) != E_OK) {
1250                 context->error = JS_E_DISPLAYNAME;
1251                 return false;
1252             }
1253         }
1254     }
1255     return true;
1256 }
1257 
JSCommitModifyExecute(napi_env env,void * data)1258 static void JSCommitModifyExecute(napi_env env, void *data)
1259 {
1260     auto *context = static_cast<FileAssetAsyncContext*>(data);
1261     MediaLibraryTracer tracer;
1262     tracer.Start("JSCommitModifyExecute");
1263     if (!CheckDisplayNameInCommitModify(context)) {
1264         return;
1265     }
1266     string uri;
1267     if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR ||
1268         context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
1269         BuildCommitModifyUriApi10(context, uri);
1270         MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
1271     } else {
1272 #ifdef MEDIALIBRARY_COMPATIBILITY
1273         BuildCommitModifyUriApi9(context, uri);
1274 #else
1275         uri = URI_UPDATE_FILE;
1276 #endif
1277     }
1278 
1279     Uri updateAssetUri(uri);
1280     MediaType mediaType = context->objectPtr->GetMediaType();
1281     string notifyUri = MediaFileUtils::GetMediaTypeUri(mediaType);
1282     DataSharePredicates predicates;
1283     DataShareValuesBucket valuesBucket;
1284     BuildCommitModifyValuesBucket(context, valuesBucket);
1285     predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ? ");
1286     predicates.SetWhereArgs({std::to_string(context->objectPtr->GetId())});
1287 
1288     int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
1289     if (changedRows < 0) {
1290         context->SaveError(changedRows);
1291         NAPI_ERR_LOG("File asset modification failed, err: %{public}d", changedRows);
1292     } else {
1293         context->changedRows = changedRows;
1294         Uri modifyNotify(notifyUri);
1295         UserFileClient::NotifyChange(modifyNotify);
1296     }
1297 }
1298 
JSCommitModifyCompleteCallback(napi_env env,napi_status status,void * data)1299 static void JSCommitModifyCompleteCallback(napi_env env, napi_status status, void *data)
1300 {
1301     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
1302     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1303     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1304     jsContext->status = false;
1305 
1306     MediaLibraryTracer tracer;
1307     tracer.Start("JSCommitModifyCompleteCallback");
1308 
1309     if (context->error == ERR_DEFAULT) {
1310         if (context->changedRows < 0) {
1311             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->changedRows,
1312                                                          "File asset modification failed");
1313             napi_get_undefined(env, &jsContext->data);
1314         } else {
1315             napi_create_int32(env, context->changedRows, &jsContext->data);
1316             jsContext->status = true;
1317             napi_get_undefined(env, &jsContext->error);
1318         }
1319     } else {
1320         NAPI_ERR_LOG("JSCommitModify fail %{public}d", context->error);
1321         context->HandleError(env, jsContext->error);
1322         napi_get_undefined(env, &jsContext->data);
1323     }
1324     tracer.Finish();
1325     if (context->work != nullptr) {
1326         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1327                                                    context->work, *jsContext);
1328     }
1329     delete context;
1330 }
GetJSArgsForCommitModify(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)1331 napi_value GetJSArgsForCommitModify(napi_env env, size_t argc, const napi_value argv[],
1332                                     FileAssetAsyncContext &asyncContext)
1333 {
1334     const int32_t refCount = 1;
1335     napi_value result = nullptr;
1336     auto context = &asyncContext;
1337     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
1338     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
1339     for (size_t i = PARAM0; i < argc; i++) {
1340         napi_valuetype valueType = napi_undefined;
1341         napi_typeof(env, argv[i], &valueType);
1342         if (i == PARAM0 && valueType == napi_function) {
1343             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
1344             break;
1345         } else {
1346             NAPI_ASSERT(env, false, "type mismatch");
1347         }
1348     }
1349     napi_get_boolean(env, true, &result);
1350     return result;
1351 }
1352 
JSCommitModify(napi_env env,napi_callback_info info)1353 napi_value FileAssetNapi::JSCommitModify(napi_env env, napi_callback_info info)
1354 {
1355     napi_status status;
1356     napi_value result = nullptr;
1357     size_t argc = ARGS_ONE;
1358     napi_value argv[ARGS_ONE] = {0};
1359     napi_value thisVar = nullptr;
1360     MediaLibraryTracer tracer;
1361     tracer.Start("JSCommitModify");
1362 
1363     GET_JS_ARGS(env, info, argc, argv, thisVar);
1364     NAPI_ASSERT(env, (argc == ARGS_ZERO || argc == ARGS_ONE), "requires 1 parameters maximum");
1365     napi_get_undefined(env, &result);
1366 
1367     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
1368     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
1369     asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
1370     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1371         result = GetJSArgsForCommitModify(env, argc, argv, *asyncContext);
1372         ASSERT_NULLPTR_CHECK(env, result);
1373         asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
1374         CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
1375 
1376         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSCommitModify", JSCommitModifyExecute,
1377             JSCommitModifyCompleteCallback);
1378     }
1379 
1380     return result;
1381 }
1382 
JSOpenExecute(napi_env env,void * data)1383 static void JSOpenExecute(napi_env env, void *data)
1384 {
1385     MediaLibraryTracer tracer;
1386     tracer.Start("JSOpenExecute");
1387 
1388     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
1389     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1390 
1391     bool isValid = false;
1392     string mode = context->valuesBucket.Get(MEDIA_FILEMODE, isValid);
1393     if (!isValid) {
1394         context->error = ERR_INVALID_OUTPUT;
1395         NAPI_ERR_LOG("getting mode invalid");
1396         return;
1397     }
1398     transform(mode.begin(), mode.end(), mode.begin(), ::tolower);
1399 
1400     string fileUri = context->objectPtr->GetUri();
1401     Uri openFileUri(fileUri);
1402     int32_t retVal = UserFileClient::OpenFile(openFileUri, mode);
1403     if (retVal <= 0) {
1404         context->SaveError(retVal);
1405         NAPI_ERR_LOG("File open asset failed, ret: %{public}d", retVal);
1406     } else {
1407         context->fd = retVal;
1408         if (mode.find('w') != string::npos) {
1409             context->objectPtr->SetOpenStatus(retVal, OPEN_TYPE_WRITE);
1410         } else {
1411             context->objectPtr->SetOpenStatus(retVal, OPEN_TYPE_READONLY);
1412         }
1413     }
1414 }
1415 
JSOpenCompleteCallback(napi_env env,napi_status status,void * data)1416 static void JSOpenCompleteCallback(napi_env env, napi_status status, void *data)
1417 {
1418     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
1419     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1420 
1421     MediaLibraryTracer tracer;
1422     tracer.Start("JSOpenCompleteCallback");
1423 
1424     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1425     jsContext->status = false;
1426 
1427     if (context->error == ERR_DEFAULT) {
1428         NAPI_DEBUG_LOG("return fd = %{public}d", context->fd);
1429         napi_create_int32(env, context->fd, &jsContext->data);
1430         napi_get_undefined(env, &jsContext->error);
1431         jsContext->status = true;
1432     } else {
1433         context->HandleError(env, jsContext->error);
1434         napi_get_undefined(env, &jsContext->data);
1435     }
1436 
1437     tracer.Finish();
1438     if (context->work != nullptr) {
1439         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1440                                                    context->work, *jsContext);
1441     }
1442 
1443     delete context;
1444 }
1445 
GetJSArgsForOpen(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)1446 napi_value GetJSArgsForOpen(napi_env env, size_t argc, const napi_value argv[],
1447                             FileAssetAsyncContext &asyncContext)
1448 {
1449     const int32_t refCount = 1;
1450     napi_value result = nullptr;
1451     auto context = &asyncContext;
1452     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
1453     size_t res = 0;
1454     char buffer[ARG_BUF_SIZE];
1455 
1456     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
1457 
1458     for (size_t i = PARAM0; i < argc; i++) {
1459         napi_valuetype valueType = napi_undefined;
1460         napi_typeof(env, argv[i], &valueType);
1461 
1462         if (i == PARAM0 && valueType == napi_string) {
1463             napi_get_value_string_utf8(env, argv[i], buffer, ARG_BUF_SIZE, &res);
1464         } else if (i == PARAM1 && valueType == napi_function) {
1465             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
1466             break;
1467         } else {
1468             NAPI_ASSERT(env, false, "type mismatch");
1469         }
1470     }
1471     context->valuesBucket.Put(MEDIA_FILEMODE, string(buffer));
1472     // Return true napi_value if params are successfully obtained
1473     napi_get_boolean(env, true, &result);
1474     return result;
1475 }
1476 
JSOpen(napi_env env,napi_callback_info info)1477 napi_value FileAssetNapi::JSOpen(napi_env env, napi_callback_info info)
1478 {
1479     napi_status status;
1480     napi_value result = nullptr;
1481     size_t argc = ARGS_TWO;
1482     napi_value argv[ARGS_TWO] = {0};
1483     napi_value thisVar = nullptr;
1484 
1485     MediaLibraryTracer tracer;
1486     tracer.Start("JSOpen");
1487 
1488     GET_JS_ARGS(env, info, argc, argv, thisVar);
1489     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
1490     napi_get_undefined(env, &result);
1491 
1492     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
1493     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
1494     if ((status == napi_ok) && (asyncContext->objectInfo != nullptr)) {
1495         asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
1496         CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
1497         result = GetJSArgsForOpen(env, argc, argv, *asyncContext);
1498         ASSERT_NULLPTR_CHECK(env, result);
1499         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSOpen", JSOpenExecute,
1500             JSOpenCompleteCallback);
1501     }
1502 
1503     return result;
1504 }
1505 
CheckFileOpenStatus(FileAssetAsyncContext * context,int fd)1506 static bool CheckFileOpenStatus(FileAssetAsyncContext *context, int fd)
1507 {
1508     auto fileAssetPtr = context->objectPtr;
1509     int ret = fileAssetPtr->GetOpenStatus(fd);
1510     if (ret < 0) {
1511         return false;
1512     } else {
1513         fileAssetPtr->RemoveOpenStatus(fd);
1514         if (ret == OPEN_TYPE_READONLY) {
1515             return false;
1516         } else {
1517             return true;
1518         }
1519     }
1520 }
1521 
JSCloseExecute(FileAssetAsyncContext * context)1522 static void JSCloseExecute(FileAssetAsyncContext *context)
1523 {
1524     MediaLibraryTracer tracer;
1525     tracer.Start("JSCloseExecute");
1526 
1527 #ifdef MEDIALIBRARY_COMPATIBILITY
1528     string closeUri;
1529     if (MediaFileUtils::IsFileTablePath(context->objectPtr->GetPath()) ||
1530         MediaFileUtils::StartsWith(context->objectPtr->GetRelativePath(), DOCS_PATH + DOC_DIR_VALUES) ||
1531         MediaFileUtils::StartsWith(context->objectPtr->GetRelativePath(), DOCS_PATH + DOWNLOAD_DIR_VALUES)) {
1532         closeUri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CLOSEASSET;
1533     } else if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
1534         context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
1535         closeUri = URI_CLOSE_PHOTO;
1536     } else if (context->objectPtr->GetMediaType() == MEDIA_TYPE_AUDIO) {
1537         closeUri = URI_CLOSE_AUDIO;
1538     } else {
1539         closeUri = URI_CLOSE_FILE;
1540     }
1541 #else
1542     string closeUri = URI_CLOSE_FILE;
1543 #endif
1544     Uri closeAssetUri(closeUri);
1545     bool isValid = false;
1546     UniqueFd unifd(context->valuesBucket.Get(MEDIA_FILEDESCRIPTOR, isValid));
1547     if (!isValid) {
1548         context->error = ERR_INVALID_OUTPUT;
1549         NAPI_ERR_LOG("getting fd is invalid");
1550         return;
1551     }
1552 
1553     if (!CheckFileOpenStatus(context, unifd.Get())) {
1554         return;
1555     }
1556 
1557     string fileUri = context->valuesBucket.Get(MEDIA_DATA_DB_URI, isValid);
1558     if (!isValid) {
1559         context->error = ERR_INVALID_OUTPUT;
1560         NAPI_ERR_LOG("getting file uri is invalid");
1561         return;
1562     }
1563     if (!MediaFileUtils::GetNetworkIdFromUri(fileUri).empty()) {
1564         return;
1565     }
1566 
1567     auto retVal = UserFileClient::Insert(closeAssetUri, context->valuesBucket);
1568     if (retVal != E_SUCCESS) {
1569         context->SaveError(retVal);
1570         NAPI_ERR_LOG("File close asset failed %{public}d", retVal);
1571     }
1572 }
1573 
JSCloseCompleteCallback(napi_env env,napi_status status,FileAssetAsyncContext * context)1574 static void JSCloseCompleteCallback(napi_env env, napi_status status,
1575                                     FileAssetAsyncContext *context)
1576 {
1577     MediaLibraryTracer tracer;
1578     tracer.Start("JSCloseCompleteCallback");
1579 
1580     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1581     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1582     jsContext->status = false;
1583 
1584     if (context->error == ERR_DEFAULT) {
1585         napi_create_int32(env, E_SUCCESS, &jsContext->data);
1586         napi_get_undefined(env, &jsContext->error);
1587         jsContext->status = true;
1588     } else {
1589         context->HandleError(env, jsContext->error);
1590         napi_get_undefined(env, &jsContext->data);
1591     }
1592 
1593     tracer.Finish();
1594     if (context->work != nullptr) {
1595         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1596                                                    context->work, *jsContext);
1597     }
1598 
1599     delete context;
1600 }
1601 
GetJSArgsForClose(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)1602 napi_value GetJSArgsForClose(napi_env env, size_t argc, const napi_value argv[],
1603                              FileAssetAsyncContext &asyncContext)
1604 {
1605     const int32_t refCount = 1;
1606     napi_value result = nullptr;
1607     auto context = &asyncContext;
1608     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
1609     int32_t fd = 0;
1610 
1611     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
1612 
1613     for (size_t i = PARAM0; i < argc; i++) {
1614         napi_valuetype valueType = napi_undefined;
1615         napi_typeof(env, argv[i], &valueType);
1616 
1617         if (i == PARAM0 && valueType == napi_number) {
1618             napi_get_value_int32(env, argv[i], &fd);
1619             if (fd <= 0) {
1620                 NAPI_ASSERT(env, false, "fd <= 0");
1621             }
1622         } else if (i == PARAM1 && valueType == napi_function) {
1623             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
1624             break;
1625         } else {
1626             NAPI_ASSERT(env, false, "type mismatch");
1627         }
1628     }
1629     context->valuesBucket.Put(MEDIA_FILEDESCRIPTOR, fd);
1630     context->valuesBucket.Put(MEDIA_DATA_DB_URI, context->objectInfo->GetFileUri());
1631     // Return true napi_value if params are successfully obtained
1632     napi_get_boolean(env, true, &result);
1633     return result;
1634 }
1635 
JSClose(napi_env env,napi_callback_info info)1636 napi_value FileAssetNapi::JSClose(napi_env env, napi_callback_info info)
1637 {
1638     napi_status status;
1639     napi_value result = nullptr;
1640     size_t argc = ARGS_TWO;
1641     napi_value argv[ARGS_TWO] = {0};
1642     napi_value thisVar = nullptr;
1643     napi_value resource = nullptr;
1644 
1645     MediaLibraryTracer tracer;
1646     tracer.Start("JSClose");
1647 
1648     GET_JS_ARGS(env, info, argc, argv, thisVar);
1649     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
1650     napi_get_undefined(env, &result);
1651     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
1652     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
1653     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1654         result = GetJSArgsForClose(env, argc, argv, *asyncContext);
1655         ASSERT_NULLPTR_CHECK(env, result);
1656         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
1657         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSClose", asyncContext);
1658 
1659         asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
1660         CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
1661 
1662         status = napi_create_async_work(
1663             env, nullptr, resource, [](napi_env env, void *data) {
1664                 auto context = static_cast<FileAssetAsyncContext*>(data);
1665                 JSCloseExecute(context);
1666             },
1667             reinterpret_cast<CompleteCallback>(JSCloseCompleteCallback),
1668             static_cast<void *>(asyncContext.get()), &asyncContext->work);
1669         if (status != napi_ok) {
1670             napi_get_undefined(env, &result);
1671         } else {
1672             napi_queue_async_work(env, asyncContext->work);
1673             asyncContext.release();
1674         }
1675     }
1676 
1677     return result;
1678 }
1679 
JSGetThumbnailExecute(FileAssetAsyncContext * context)1680 static void JSGetThumbnailExecute(FileAssetAsyncContext* context)
1681 {
1682     MediaLibraryTracer tracer;
1683     tracer.Start("JSGetThumbnailExecute");
1684 
1685     string path = context->objectPtr->GetPath();
1686 #ifndef MEDIALIBRARY_COMPATIBILITY
1687     if (path.empty()
1688             && !context->objectPtr->GetRelativePath().empty() && !context->objectPtr->GetDisplayName().empty()) {
1689         path = ROOT_MEDIA_DIR + context->objectPtr->GetRelativePath() + context->objectPtr->GetDisplayName();
1690     }
1691 #endif
1692     context->pixelmap = ThumbnailManager::QueryThumbnail(context->objectPtr->GetUri(), context->size, path);
1693 }
1694 
JSGetThumbnailCompleteCallback(napi_env env,napi_status status,FileAssetAsyncContext * context)1695 static void JSGetThumbnailCompleteCallback(napi_env env, napi_status status,
1696                                            FileAssetAsyncContext* context)
1697 {
1698     MediaLibraryTracer tracer;
1699     tracer.Start("JSGetThumbnailCompleteCallback");
1700 
1701     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1702 
1703     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1704     jsContext->status = false;
1705 
1706     if (context->error == ERR_DEFAULT) {
1707         if (context->pixelmap != nullptr) {
1708             jsContext->data = Media::PixelMapNapi::CreatePixelMap(env, context->pixelmap);
1709             napi_get_undefined(env, &jsContext->error);
1710             jsContext->status = true;
1711         } else {
1712             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1713                 "Get thumbnail failed");
1714             napi_get_undefined(env, &jsContext->data);
1715         }
1716     } else {
1717         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1718             "Ability helper or thumbnail helper is null");
1719         napi_get_undefined(env, &jsContext->data);
1720     }
1721 
1722     tracer.Finish();
1723     if (context->work != nullptr) {
1724         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1725                                                    context->work, *jsContext);
1726     }
1727 
1728     delete context;
1729 }
1730 
GetInt32InfoFromNapiObject(napi_env env,napi_value configObj,std::string type,int32_t & result)1731 static bool GetInt32InfoFromNapiObject(napi_env env, napi_value configObj, std::string type, int32_t &result)
1732 {
1733     napi_value item = nullptr;
1734     bool exist = false;
1735     napi_status status = napi_has_named_property(env, configObj, type.c_str(), &exist);
1736     if (status != napi_ok || !exist) {
1737         NAPI_ERR_LOG("can not find named property, status: %{public}d", status);
1738         return false;
1739     }
1740 
1741     if (napi_get_named_property(env, configObj, type.c_str(), &item) != napi_ok) {
1742         NAPI_ERR_LOG("get named property fail");
1743         return false;
1744     }
1745 
1746     if (napi_get_value_int32(env, item, &result) != napi_ok) {
1747         NAPI_ERR_LOG("get property value fail");
1748         return false;
1749     }
1750 
1751     return true;
1752 }
1753 
GetNapiObjectFromNapiObject(napi_env env,napi_value configObj,std::string type,napi_value * object)1754 static bool GetNapiObjectFromNapiObject(napi_env env, napi_value configObj, std::string type, napi_value *object)
1755 {
1756     bool exist = false;
1757     napi_status status = napi_has_named_property(env, configObj, type.c_str(), &exist);
1758     if (status != napi_ok || !exist) {
1759         NAPI_ERR_LOG("can not find named property, status: %{public}d", status);
1760         return false;
1761     }
1762 
1763     if (napi_get_named_property(env, configObj, type.c_str(), object) != napi_ok) {
1764         NAPI_ERR_LOG("get named property fail");
1765         return false;
1766     }
1767 
1768     return true;
1769 }
1770 
GetJSArgsForGetThumbnail(napi_env env,size_t argc,const napi_value argv[],unique_ptr<FileAssetAsyncContext> & asyncContext)1771 napi_value GetJSArgsForGetThumbnail(napi_env env, size_t argc, const napi_value argv[],
1772                                     unique_ptr<FileAssetAsyncContext> &asyncContext)
1773 {
1774     asyncContext->size.width = DEFAULT_THUMB_SIZE;
1775     asyncContext->size.height = DEFAULT_THUMB_SIZE;
1776 
1777     if (argc == ARGS_ONE) {
1778         napi_valuetype valueType = napi_undefined;
1779         if (napi_typeof(env, argv[PARAM0], &valueType) == napi_ok &&
1780             (valueType == napi_undefined || valueType == napi_null)) {
1781             argc -= 1;
1782         }
1783     }
1784 
1785     for (size_t i = PARAM0; i < argc; i++) {
1786         napi_valuetype valueType = napi_undefined;
1787         napi_typeof(env, argv[i], &valueType);
1788 
1789         if (i == PARAM0 && valueType == napi_object) {
1790             GetInt32InfoFromNapiObject(env, argv[PARAM0], "width", asyncContext->size.width);
1791             GetInt32InfoFromNapiObject(env, argv[PARAM0], "height", asyncContext->size.height);
1792         } else if (i == PARAM0 && valueType == napi_function) {
1793             napi_create_reference(env, argv[i], NAPI_INIT_REF_COUNT, &asyncContext->callbackRef);
1794             break;
1795         } else if (i == PARAM1 && valueType == napi_function) {
1796             napi_create_reference(env, argv[i], NAPI_INIT_REF_COUNT, &asyncContext->callbackRef);
1797             break;
1798         } else {
1799             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Invalid parameter type");
1800             return nullptr;
1801         }
1802     }
1803 
1804     napi_value result = nullptr;
1805     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1806     return result;
1807 }
1808 
GetPhotoRequestOption(napi_env env,napi_value object,unique_ptr<FileAssetAsyncContext> & asyncContext,RequestPhotoType & type)1809 static napi_value GetPhotoRequestOption(napi_env env, napi_value object,
1810     unique_ptr<FileAssetAsyncContext> &asyncContext, RequestPhotoType &type)
1811 {
1812     napi_value sizeObj;
1813     if (GetNapiObjectFromNapiObject(env, object, "size", &sizeObj)) {
1814         GetInt32InfoFromNapiObject(env, sizeObj, "width", asyncContext->size.width);
1815         GetInt32InfoFromNapiObject(env, sizeObj, "height", asyncContext->size.height);
1816     }
1817     int32_t requestType = 0;
1818     if (GetInt32InfoFromNapiObject(env, object, REQUEST_PHOTO_TYPE, requestType)) {
1819         if (requestType >= static_cast<int>(RequestPhotoType::REQUEST_TYPE_END)) {
1820             NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Invalid parameter type");
1821             return nullptr;
1822         }
1823         type = static_cast<RequestPhotoType>(requestType);
1824     } else {
1825         type = RequestPhotoType::REQUEST_ALL_THUMBNAILS;
1826     }
1827 
1828     napi_value result = nullptr;
1829     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1830     return result;
1831 }
1832 
GetPhotoRequestArgs(napi_env env,size_t argc,const napi_value argv[],unique_ptr<FileAssetAsyncContext> & asyncContext,RequestPhotoType & type)1833 napi_value GetPhotoRequestArgs(napi_env env, size_t argc, const napi_value argv[],
1834     unique_ptr<FileAssetAsyncContext> &asyncContext, RequestPhotoType &type)
1835 {
1836     if (argc != ARGS_ONE && argc != ARGS_TWO) {
1837         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Invalid parameter number " + to_string(argc));
1838         return nullptr;
1839     }
1840     asyncContext->size.width = DEFAULT_THUMB_SIZE;
1841     asyncContext->size.height = DEFAULT_THUMB_SIZE;
1842 
1843     for (size_t i = PARAM0; i < argc; i++) {
1844         napi_valuetype valueType = napi_undefined;
1845         napi_typeof(env, argv[i], &valueType);
1846 
1847         if (argc == PARAM1) {
1848             if (valueType == napi_function) {
1849                 napi_create_reference(env, argv[i], NAPI_INIT_REF_COUNT, &asyncContext->callbackRef);
1850                 break;
1851             } else {
1852                 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Invalid parameter type");
1853                 return nullptr;
1854             }
1855         }
1856         if (i == PARAM0 && valueType == napi_object) {
1857             napi_value result = GetPhotoRequestOption(env, argv[i], asyncContext, type);
1858             ASSERT_NULLPTR_CHECK(env, result);
1859         } else if (i == PARAM1 && valueType == napi_function) {
1860             napi_create_reference(env, argv[i], NAPI_INIT_REF_COUNT, &asyncContext->callbackRef);
1861             break;
1862         } else {
1863             NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Invalid parameter type");
1864             return nullptr;
1865         }
1866     }
1867 
1868     napi_value result = nullptr;
1869     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1870     return result;
1871 }
1872 
JSGetThumbnail(napi_env env,napi_callback_info info)1873 napi_value FileAssetNapi::JSGetThumbnail(napi_env env, napi_callback_info info)
1874 {
1875     napi_status status;
1876     napi_value result = nullptr;
1877     size_t argc = ARGS_TWO;
1878     napi_value argv[ARGS_TWO] = {0};
1879     napi_value thisVar = nullptr;
1880     napi_value resource = nullptr;
1881 
1882     MediaLibraryTracer tracer;
1883     tracer.Start("JSGetThumbnail");
1884 
1885     GET_JS_ARGS(env, info, argc, argv, thisVar);
1886     NAPI_ASSERT(env, (argc == ARGS_ZERO || argc == ARGS_ONE || argc == ARGS_TWO),
1887         "requires 2 parameters maximum");
1888     napi_get_undefined(env, &result);
1889     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
1890     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
1891     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1892         result = GetJSArgsForGetThumbnail(env, argc, argv, asyncContext);
1893         CHECK_NULLPTR_RET(result);
1894         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
1895         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSGetThumbnail", asyncContext);
1896         asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
1897         CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
1898 
1899         status = napi_create_async_work(
1900             env, nullptr, resource, [](napi_env env, void *data) {
1901                 auto context = static_cast<FileAssetAsyncContext*>(data);
1902                 JSGetThumbnailExecute(context);
1903             },
1904             reinterpret_cast<CompleteCallback>(JSGetThumbnailCompleteCallback),
1905             static_cast<void *>(asyncContext.get()), &asyncContext->work);
1906         if (status != napi_ok) {
1907             napi_get_undefined(env, &result);
1908         } else {
1909             napi_queue_async_work(env, asyncContext->work);
1910             asyncContext.release();
1911         }
1912     }
1913 
1914     return result;
1915 }
1916 
1917 static const map<int32_t, struct AnalysisSourceInfo> ANALYSIS_SOURCE_INFO_MAP = {
1918     { ANALYSIS_AESTHETICS_SCORE, { PAH_QUERY_ANA_ATTS, { AESTHETICS_SCORE, PROB } } },
1919     { ANALYSIS_LABEL, { PAH_QUERY_ANA_LABEL, { CATEGORY_ID, SUB_LABEL, PROB, FEATURE, SIM_RESULT } } },
1920     { ANALYSIS_OCR, { PAH_QUERY_ANA_OCR, { OCR_TEXT, OCR_TEXT_MSG, OCR_WIDTH, OCR_HEIGHT } } },
1921     { ANALYSIS_FACE, { PAH_QUERY_ANA_FACE, { FACE_ID, TAG_ID, SCALE_X, SCALE_Y, SCALE_WIDTH, SCALE_HEIGHT, LANDMARKS,
1922         PITCH, YAW, ROLL, PROB, TOTAL_FACES, FEATURES } } },
1923     { ANALYSIS_OBJECT, { PAH_QUERY_ANA_OBJECT, { OBJECT_ID, OBJECT_LABEL, OBJECT_SCALE_X, OBJECT_SCALE_Y,
1924         OBJECT_SCALE_WIDTH, OBJECT_SCALE_HEIGHT, PROB } } },
1925     { ANALYSIS_RECOMMENDATION, { PAH_QUERY_ANA_RECOMMENDATION, { RECOMMENDATION_ID, RECOMMENDATION_RESOLUTION,
1926         RECOMMENDATION_SCALE_X, RECOMMENDATION_SCALE_Y, RECOMMENDATION_SCALE_WIDTH, RECOMMENDATION_SCALE_HEIGHT } } },
1927     { ANALYSIS_SEGMENTATION, { PAH_QUERY_ANA_SEGMENTATION, { SEGMENTATION_AREA } } },
1928     { ANALYSIS_COMPOSITION, { PAH_QUERY_ANA_COMPOSITION, { COMPOSITION_ID, COMPOSITION_RESOLUTION, CLOCK_STYLE,
1929         CLOCK_LOCATION_X, CLOCK_LOCATION_Y, CLOCK_COLOUR, COMPOSITION_SCALE_X, COMPOSITION_SCALE_Y,
1930         COMPOSITION_SCALE_WIDTH, COMPOSITION_SCALE_HEIGHT } } },
1931     { ANALYSIS_SALIENCY, { PAH_QUERY_ANA_SAL, { SALIENCY_X, SALIENCY_Y } } },
1932     { ANALYSIS_DETAIL_ADDRESS, { PAH_QUERY_ANA_ADDRESS, { PhotoColumn::PHOTOS_TABLE + "." + LATITUDE,
1933         PhotoColumn::PHOTOS_TABLE + "." + LONGITUDE, LANGUAGE, COUNTRY, ADMIN_AREA, SUB_ADMIN_AREA,
1934         LOCALITY, SUB_LOCALITY, THOROUGHFARE, SUB_THOROUGHFARE, FEATURE_NAME, CITY_NAME, ADDRESS_DESCRIPTION } } },
1935 };
1936 
JSGetAnalysisDataExecute(FileAssetAsyncContext * context)1937 static void JSGetAnalysisDataExecute(FileAssetAsyncContext* context)
1938 {
1939     MediaLibraryTracer tracer;
1940     tracer.Start("JSGetThumbnailExecute");
1941     string uriStr;
1942     std::vector<std::string> fetchColumn;
1943     DataShare::DataSharePredicates predicates;
1944     if (ANALYSIS_SOURCE_INFO_MAP.find(context->analysisType) != ANALYSIS_SOURCE_INFO_MAP.end()) {
1945         uriStr = ANALYSIS_SOURCE_INFO_MAP.at(context->analysisType).uriStr;
1946         fetchColumn = ANALYSIS_SOURCE_INFO_MAP.at(context->analysisType).fetchColumn;
1947         if (context->analysisType == ANALYSIS_DETAIL_ADDRESS) {
1948             string language = Global::I18n::LocaleConfig::GetSystemLanguage();
1949             vector<string> onClause = {
1950                 PhotoColumn::PHOTOS_TABLE + "." + PhotoColumn::PHOTO_LATITUDE + " = " +
1951                 GEO_KNOWLEDGE_TABLE + "." + LATITUDE + " AND " + PhotoColumn::PHOTOS_TABLE + "." +
1952                 PhotoColumn::PHOTO_LONGITUDE + " = " + GEO_KNOWLEDGE_TABLE + "." + LONGITUDE +
1953                 " AND " + GEO_KNOWLEDGE_TABLE + "." + LANGUAGE + " = \"" + language + "\""
1954             };
1955             predicates.LeftOuterJoin(GEO_KNOWLEDGE_TABLE)->On(onClause);
1956         }
1957     } else {
1958         NAPI_ERR_LOG("Invalid analysisType");
1959         return;
1960     }
1961     int fileId = context->objectInfo->GetFileId();
1962     Uri uri (uriStr);
1963     predicates.EqualTo(MediaColumn::MEDIA_ID, to_string(fileId));
1964     int errCode = 0;
1965     auto resultSet = UserFileClient::Query(uri, predicates, fetchColumn, errCode);
1966     context->analysisData = MediaLibraryNapiUtils::ParseResultSet2JsonStr(resultSet, fetchColumn);
1967 }
1968 
JSFavoriteCallbackComplete(napi_env env,napi_status status,void * data)1969 static void JSFavoriteCallbackComplete(napi_env env, napi_status status, void *data)
1970 {
1971     MediaLibraryTracer tracer;
1972     tracer.Start("JSFavoriteCallbackComplete");
1973 
1974     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
1975     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1976     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1977     CHECK_NULL_PTR_RETURN_VOID(jsContext, "jsContext context is null");
1978     jsContext->status = false;
1979     napi_get_undefined(env, &jsContext->data);
1980     if (context->error == ERR_DEFAULT) {
1981         jsContext->status = true;
1982         Media::MediaType mediaType = context->objectPtr->GetMediaType();
1983         string notifyUri = MediaFileUtils::GetMediaTypeUri(mediaType);
1984         Uri modifyNotify(notifyUri);
1985         UserFileClient::NotifyChange(modifyNotify);
1986     } else {
1987         context->HandleError(env, jsContext->error);
1988         napi_get_undefined(env, &jsContext->data);
1989     }
1990 
1991     tracer.Finish();
1992     if (context->work != nullptr) {
1993         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1994                                                    context->work, *jsContext);
1995     }
1996 
1997     delete context;
1998 }
1999 
GetIsDirectoryiteNative(napi_env env,const FileAssetAsyncContext & fileContext)2000 static bool GetIsDirectoryiteNative(napi_env env, const FileAssetAsyncContext &fileContext)
2001 {
2002     MediaLibraryTracer tracer;
2003     tracer.Start("GetIsDirectoryiteNative");
2004 
2005     FileAssetAsyncContext *context = const_cast<FileAssetAsyncContext *>(&fileContext);
2006     if (context == nullptr) {
2007         NAPI_ERR_LOG("Async context is null");
2008         return false;
2009     }
2010 
2011 #ifdef MEDIALIBRARY_COMPATIBILITY
2012     if ((context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_AUDIO) ||
2013         (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_IMAGE) ||
2014         (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_VIDEO)) {
2015         context->status = true;
2016         return false;
2017     }
2018 
2019     int64_t virtualId = MediaFileUtils::GetVirtualIdByType(context->objectPtr->GetId(), MediaType::MEDIA_TYPE_FILE);
2020     vector<string> selectionArgs = { to_string(virtualId) };
2021 #else
2022     vector<string> selectionArgs = { to_string(context->objectPtr->GetId()) };
2023 #endif
2024     vector<string> columns = { MEDIA_DATA_DB_MEDIA_TYPE };
2025     DataSharePredicates predicates;
2026     predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ?");
2027     predicates.SetWhereArgs(selectionArgs);
2028     string queryUri = MEDIALIBRARY_DATA_URI;
2029     Uri uri(queryUri);
2030     int errCode = 0;
2031     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
2032     if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
2033         NAPI_ERR_LOG("Query IsDirectory failed");
2034         return false;
2035     }
2036     int32_t index = 0;
2037     if (resultSet->GetColumnIndex(MEDIA_DATA_DB_MEDIA_TYPE, index) != NativeRdb::E_OK) {
2038         NAPI_ERR_LOG("Query Directory failed");
2039         return false;
2040     }
2041     int32_t mediaType = 0;
2042     if (resultSet->GetInt(index, mediaType) != NativeRdb::E_OK) {
2043         NAPI_ERR_LOG("Can not get file path");
2044         return false;
2045     }
2046     context->status = true;
2047     return  mediaType == static_cast<int>(MediaType::MEDIA_TYPE_ALBUM);
2048 }
2049 
JSIsDirectoryCallbackComplete(napi_env env,napi_status status,FileAssetAsyncContext * context)2050 static void JSIsDirectoryCallbackComplete(napi_env env, napi_status status,
2051                                           FileAssetAsyncContext* context)
2052 {
2053     MediaLibraryTracer tracer;
2054     tracer.Start("JSIsDirectoryCallbackComplete");
2055 
2056     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2057     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2058     CHECK_NULL_PTR_RETURN_VOID(jsContext, "jsContext context is null");
2059     jsContext->status = false;
2060 
2061     if (context->status) {
2062         napi_get_boolean(env, context->isDirectory, &jsContext->data);
2063         napi_get_undefined(env, &jsContext->error);
2064         jsContext->status = true;
2065     } else {
2066         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
2067                                                      "UserFileClient is invalid");
2068         napi_get_undefined(env, &jsContext->data);
2069     }
2070 
2071     tracer.Finish();
2072     if (context->work != nullptr) {
2073         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2074                                                    context->work, *jsContext);
2075     }
2076 
2077     delete context;
2078 }
2079 
GetJSArgsForIsDirectory(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)2080 static napi_value GetJSArgsForIsDirectory(napi_env env, size_t argc, const napi_value argv[],
2081                                           FileAssetAsyncContext &asyncContext)
2082 {
2083     const int32_t refCount = 1;
2084     napi_value result;
2085     auto context = &asyncContext;
2086     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2087     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2088     for (size_t i = PARAM0; i < argc; i++) {
2089         napi_valuetype valueType = napi_undefined;
2090         napi_typeof(env, argv[i], &valueType);
2091         if (i == PARAM0 && valueType == napi_function) {
2092             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2093             break;
2094         } else {
2095             NAPI_ASSERT(env, false, "type mismatch");
2096         }
2097     }
2098     napi_get_boolean(env, true, &result);
2099     return result;
2100 }
2101 
JSIsDirectory(napi_env env,napi_callback_info info)2102 napi_value FileAssetNapi::JSIsDirectory(napi_env env, napi_callback_info info)
2103 {
2104     size_t argc = ARGS_ONE;
2105     napi_value argv[ARGS_ONE] = {0};
2106     napi_value thisVar = nullptr;
2107     napi_value resource = nullptr;
2108 
2109     MediaLibraryTracer tracer;
2110     tracer.Start("JSisDirectory");
2111 
2112     GET_JS_ARGS(env, info, argc, argv, thisVar);
2113     NAPI_ASSERT(env, (argc == ARGS_ZERO || argc == ARGS_ONE), "requires 2 parameters maximum");
2114     napi_value result = nullptr;
2115     napi_get_undefined(env, &result);
2116     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2117     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
2118     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2119     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2120         result = GetJSArgsForIsDirectory(env, argc, argv, *asyncContext);
2121         ASSERT_NULLPTR_CHECK(env, result);
2122         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
2123         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSIsDirectory", asyncContext);
2124         asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2125         CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
2126         status = napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {
2127                 FileAssetAsyncContext* context = static_cast<FileAssetAsyncContext*>(data);
2128                 context->status = false;
2129                 context->isDirectory = GetIsDirectoryiteNative(env, *context);
2130             },
2131             reinterpret_cast<CompleteCallback>(JSIsDirectoryCallbackComplete),
2132             static_cast<void *>(asyncContext.get()), &asyncContext->work);
2133         if (status != napi_ok) {
2134             napi_get_undefined(env, &result);
2135         } else {
2136             napi_queue_async_work(env, asyncContext->work);
2137             asyncContext.release();
2138         }
2139     }
2140     return result;
2141 }
2142 
JSIsFavoriteExecute(FileAssetAsyncContext * context)2143 static void JSIsFavoriteExecute(FileAssetAsyncContext* context)
2144 {
2145     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2146     context->isFavorite = context->objectPtr->IsFavorite();
2147     return;
2148 }
2149 
JSIsFavoriteCallbackComplete(napi_env env,napi_status status,FileAssetAsyncContext * context)2150 static void JSIsFavoriteCallbackComplete(napi_env env, napi_status status,
2151                                          FileAssetAsyncContext* context)
2152 {
2153     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2154     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2155     CHECK_NULL_PTR_RETURN_VOID(jsContext, "jsContext context is null");
2156     jsContext->status = false;
2157     if (context->error == ERR_DEFAULT) {
2158         napi_get_boolean(env, context->isFavorite, &jsContext->data);
2159         napi_get_undefined(env, &jsContext->error);
2160         jsContext->status = true;
2161     } else {
2162         NAPI_ERR_LOG("Get IsFavorite failed, ret: %{public}d", context->error);
2163         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
2164             "UserFileClient is invalid");
2165         napi_get_undefined(env, &jsContext->data);
2166     }
2167     if (context->work != nullptr) {
2168         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2169                                                    context->work, *jsContext);
2170     }
2171     delete context;
2172 }
2173 
GetJSArgsForFavorite(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)2174 napi_value GetJSArgsForFavorite(napi_env env, size_t argc, const napi_value argv[],
2175                                 FileAssetAsyncContext &asyncContext)
2176 {
2177     const int32_t refCount = 1;
2178     napi_value result = nullptr;
2179     auto context = &asyncContext;
2180     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2181     bool isFavorite = false;
2182     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2183     for (size_t i = PARAM0; i < argc; i++) {
2184         napi_valuetype valueType = napi_undefined;
2185         napi_typeof(env, argv[i], &valueType);
2186         if (i == PARAM0 && valueType == napi_boolean) {
2187             napi_get_value_bool(env, argv[i], &isFavorite);
2188         } else if (i == PARAM1 && valueType == napi_function) {
2189             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2190             break;
2191         } else {
2192             NAPI_ASSERT(env, false, "type mismatch");
2193         }
2194     }
2195     context->isFavorite = isFavorite;
2196     napi_get_boolean(env, true, &result);
2197     return result;
2198 }
2199 
2200 #ifdef MEDIALIBRARY_COMPATIBILITY
FavoriteByUpdate(FileAssetAsyncContext * context)2201 static void FavoriteByUpdate(FileAssetAsyncContext *context)
2202 {
2203     DataShareValuesBucket valuesBucket;
2204     string uriString;
2205     if ((context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_IMAGE) ||
2206         (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_VIDEO)) {
2207         uriString = URI_UPDATE_PHOTO;
2208     } else {
2209         uriString = URI_UPDATE_AUDIO;
2210     }
2211     valuesBucket.Put(MEDIA_DATA_DB_IS_FAV, (context->isFavorite ? IS_FAV : NOT_FAV));
2212     DataSharePredicates predicates;
2213     int32_t fileId = context->objectPtr->GetId();
2214     predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ? ");
2215     predicates.SetWhereArgs({ to_string(fileId) });
2216     Uri uri(uriString);
2217     context->changedRows = UserFileClient::Update(uri, predicates, valuesBucket);
2218 }
2219 #endif
2220 
FavoriteByInsert(FileAssetAsyncContext * context)2221 static void FavoriteByInsert(FileAssetAsyncContext *context)
2222 {
2223     DataShareValuesBucket valuesBucket;
2224     string uriString = MEDIALIBRARY_DATA_URI + "/" + MEDIA_SMARTALBUMMAPOPRN + "/";
2225     uriString += context->isFavorite ? MEDIA_SMARTALBUMMAPOPRN_ADDSMARTALBUM : MEDIA_SMARTALBUMMAPOPRN_REMOVESMARTALBUM;
2226     valuesBucket.Put(SMARTALBUMMAP_DB_ALBUM_ID, FAVOURITE_ALBUM_ID_VALUES);
2227     valuesBucket.Put(SMARTALBUMMAP_DB_CHILD_ASSET_ID, context->objectPtr->GetId());
2228     Uri uri(uriString);
2229     context->changedRows = UserFileClient::Insert(uri, valuesBucket);
2230 }
2231 
JSFavouriteExecute(napi_env env,void * data)2232 static void JSFavouriteExecute(napi_env env, void *data)
2233 {
2234     MediaLibraryTracer tracer;
2235     tracer.Start("JSFavouriteExecute");
2236 
2237     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
2238     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2239 
2240 #ifdef MEDIALIBRARY_COMPATIBILITY
2241     string uriString = MEDIALIBRARY_DATA_URI + "/";
2242     if ((context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_IMAGE) ||
2243         (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_VIDEO) ||
2244         (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_AUDIO)) {
2245         if (MediaFileUtils::IsFileTablePath(context->objectPtr->GetPath())) {
2246             FavoriteByInsert(context);
2247         } else {
2248             FavoriteByUpdate(context);
2249         }
2250     } else {
2251         FavoriteByInsert(context);
2252     }
2253 #else
2254     FavoriteByInsert(context);
2255 #endif
2256     if (context->changedRows >= 0) {
2257         context->objectPtr->SetFavorite(context->isFavorite);
2258     }
2259     context->SaveError(context->changedRows);
2260 }
2261 
JSFavorite(napi_env env,napi_callback_info info)2262 napi_value FileAssetNapi::JSFavorite(napi_env env, napi_callback_info info)
2263 {
2264     size_t argc = ARGS_TWO;
2265     napi_value argv[ARGS_TWO] = {0};
2266     napi_value thisVar = nullptr;
2267 
2268     MediaLibraryTracer tracer;
2269     tracer.Start("JSFavorite");
2270 
2271     GET_JS_ARGS(env, info, argc, argv, thisVar);
2272     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
2273     napi_value result = nullptr;
2274     napi_get_undefined(env, &result);
2275 
2276     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2277     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
2278     asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
2279     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2280     if ((status != napi_ok) || (asyncContext->objectInfo == nullptr)) {
2281         NAPI_DEBUG_LOG("get this Var fail");
2282         return result;
2283     }
2284 
2285     result = GetJSArgsForFavorite(env, argc, argv, *asyncContext);
2286     if (asyncContext->isFavorite == asyncContext->objectInfo->IsFavorite()) {
2287         NAPI_DEBUG_LOG("favorite state is the same");
2288         return result;
2289     }
2290     ASSERT_NULLPTR_CHECK(env, result);
2291     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2292     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
2293 
2294     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSFavorite", JSFavouriteExecute,
2295         JSFavoriteCallbackComplete);
2296 }
2297 
GetJSArgsForIsFavorite(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)2298 static napi_value GetJSArgsForIsFavorite(napi_env env, size_t argc, const napi_value argv[],
2299                                          FileAssetAsyncContext &asyncContext)
2300 {
2301     const int32_t refCount = 1;
2302     napi_value result;
2303     auto context = &asyncContext;
2304     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2305     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2306     for (size_t i = PARAM0; i < argc; i++) {
2307         napi_valuetype valueType = napi_undefined;
2308         napi_typeof(env, argv[i], &valueType);
2309         if (i == PARAM0 && valueType == napi_function) {
2310             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2311             break;
2312         } else {
2313             NAPI_ASSERT(env, false, "type mismatch");
2314         }
2315     }
2316     napi_get_boolean(env, true, &result);
2317     return result;
2318 }
2319 
JSIsFavorite(napi_env env,napi_callback_info info)2320 napi_value FileAssetNapi::JSIsFavorite(napi_env env, napi_callback_info info)
2321 {
2322     MediaLibraryTracer tracer;
2323     tracer.Start("JSIsFavorite");
2324 
2325     napi_status status;
2326     napi_value result = nullptr;
2327     size_t argc = ARGS_ONE;
2328     napi_value argv[ARGS_ONE] = {0};
2329     napi_value thisVar = nullptr;
2330     napi_value resource = nullptr;
2331     GET_JS_ARGS(env, info, argc, argv, thisVar);
2332     NAPI_ASSERT(env, (argc == ARGS_ZERO || argc == ARGS_ONE), "requires 1 parameters maximum");
2333     napi_get_undefined(env, &result);
2334     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2335     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
2336     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2337     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2338         result = GetJSArgsForIsFavorite(env, argc, argv, *asyncContext);
2339         ASSERT_NULLPTR_CHECK(env, result);
2340         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
2341         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSIsFavorite", asyncContext);
2342         asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2343         CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
2344 
2345         status = napi_create_async_work(
2346             env, nullptr, resource, [](napi_env env, void *data) {
2347                 auto context = static_cast<FileAssetAsyncContext*>(data);
2348                 JSIsFavoriteExecute(context);
2349             },
2350             reinterpret_cast<CompleteCallback>(JSIsFavoriteCallbackComplete),
2351             static_cast<void *>(asyncContext.get()), &asyncContext->work);
2352         if (status != napi_ok) {
2353             napi_get_undefined(env, &result);
2354         } else {
2355             napi_queue_async_work(env, asyncContext->work);
2356             asyncContext.release();
2357         }
2358     }
2359     return result;
2360 }
2361 
TrashByUpdate(FileAssetAsyncContext * context)2362 static void TrashByUpdate(FileAssetAsyncContext *context)
2363 {
2364     DataShareValuesBucket valuesBucket;
2365     string uriString;
2366     if ((context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_IMAGE) ||
2367         (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_VIDEO)) {
2368         uriString = URI_UPDATE_PHOTO;
2369     } else {
2370         uriString = URI_UPDATE_AUDIO;
2371     }
2372     valuesBucket.Put(MEDIA_DATA_DB_DATE_TRASHED,
2373         (context->isTrash ? MediaFileUtils::UTCTimeMilliSeconds() : NOT_TRASH));
2374     DataSharePredicates predicates;
2375     int32_t fileId = context->objectPtr->GetId();
2376     predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ? ");
2377     predicates.SetWhereArgs({ to_string(fileId) });
2378     Uri uri(uriString);
2379     context->changedRows = UserFileClient::Update(uri, predicates, valuesBucket);
2380 }
2381 
TrashByInsert(FileAssetAsyncContext * context)2382 static void TrashByInsert(FileAssetAsyncContext *context)
2383 {
2384     DataShareValuesBucket valuesBucket;
2385     string uriString = MEDIALIBRARY_DATA_URI + "/" + MEDIA_SMARTALBUMMAPOPRN + "/";
2386     uriString += context->isTrash ? MEDIA_SMARTALBUMMAPOPRN_ADDSMARTALBUM : MEDIA_SMARTALBUMMAPOPRN_REMOVESMARTALBUM;
2387     valuesBucket.Put(SMARTALBUMMAP_DB_ALBUM_ID, TRASH_ALBUM_ID_VALUES);
2388     valuesBucket.Put(SMARTALBUMMAP_DB_CHILD_ASSET_ID, context->objectPtr->GetId());
2389     Uri uri(uriString);
2390     context->changedRows = UserFileClient::Insert(uri, valuesBucket);
2391 }
2392 
JSTrashExecute(napi_env env,void * data)2393 static void JSTrashExecute(napi_env env, void *data)
2394 {
2395     MediaLibraryTracer tracer;
2396     tracer.Start("JSTrashExecute");
2397 
2398     auto *context = static_cast<FileAssetAsyncContext*>(data);
2399 
2400 #ifdef MEDIALIBRARY_COMPATIBILITY
2401     if ((context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_IMAGE) ||
2402         (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_VIDEO) ||
2403         (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_AUDIO)) {
2404         if (MediaFileUtils::IsFileTablePath(context->objectPtr->GetPath())) {
2405             TrashByInsert(context);
2406         } else {
2407             TrashByUpdate(context);
2408         }
2409     } else {
2410         TrashByInsert(context);
2411     }
2412 #else
2413     TrashByInsert(context);
2414 #endif
2415     if (context->changedRows >= 0) {
2416         int32_t trashFlag = (context->isTrash ? IS_TRASH : NOT_TRASH);
2417         context->objectPtr->SetIsTrash(trashFlag);
2418     }
2419     context->SaveError(context->changedRows);
2420 }
2421 
JSTrashCallbackComplete(napi_env env,napi_status status,void * data)2422 static void JSTrashCallbackComplete(napi_env env, napi_status status, void *data)
2423 {
2424     MediaLibraryTracer tracer;
2425     tracer.Start("JSTrashCallbackComplete");
2426 
2427     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
2428     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2429     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2430     CHECK_NULL_PTR_RETURN_VOID(jsContext, "jsContext context is null");
2431     jsContext->status = false;
2432     napi_get_undefined(env, &jsContext->data);
2433     if (context->error == ERR_DEFAULT) {
2434         jsContext->status = true;
2435         Media::MediaType mediaType = context->objectPtr->GetMediaType();
2436         string notifyUri = MediaFileUtils::GetMediaTypeUri(mediaType);
2437         Uri modifyNotify(notifyUri);
2438         UserFileClient::NotifyChange(modifyNotify);
2439         NAPI_DEBUG_LOG("JSTrashCallbackComplete success");
2440     } else {
2441         context->HandleError(env, jsContext->error);
2442     }
2443 
2444     tracer.Finish();
2445     if (context->work != nullptr) {
2446         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2447                                                    context->work, *jsContext);
2448     }
2449 
2450     delete context;
2451 }
2452 
GetJSArgsForTrash(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)2453 napi_value GetJSArgsForTrash(napi_env env, size_t argc, const napi_value argv[],
2454                              FileAssetAsyncContext &asyncContext)
2455 {
2456     const int32_t refCount = 1;
2457     napi_value result = nullptr;
2458     auto context = &asyncContext;
2459     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2460     bool isTrash = false;
2461     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2462     for (size_t i = PARAM0; i < argc; i++) {
2463         napi_valuetype valueType = napi_undefined;
2464         napi_typeof(env, argv[i], &valueType);
2465         if (i == PARAM0 && valueType == napi_boolean) {
2466             napi_get_value_bool(env, argv[i], &isTrash);
2467         } else if (i == PARAM1 && valueType == napi_function) {
2468             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2469             break;
2470         } else {
2471             NAPI_ASSERT(env, false, "type mismatch");
2472         }
2473     }
2474     context->isTrash = isTrash;
2475     napi_get_boolean(env, true, &result);
2476     return result;
2477 }
2478 
JSTrash(napi_env env,napi_callback_info info)2479 napi_value FileAssetNapi::JSTrash(napi_env env, napi_callback_info info)
2480 {
2481     napi_status status;
2482     napi_value result = nullptr;
2483     size_t argc = ARGS_TWO;
2484     napi_value argv[ARGS_TWO] = {0};
2485     napi_value thisVar = nullptr;
2486 
2487     MediaLibraryTracer tracer;
2488     tracer.Start("JSTrash");
2489 
2490     GET_JS_ARGS(env, info, argc, argv, thisVar);
2491     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
2492 
2493     napi_get_undefined(env, &result);
2494     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2495     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
2496     asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
2497     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2498     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2499         result = GetJSArgsForTrash(env, argc, argv, *asyncContext);
2500         ASSERT_NULLPTR_CHECK(env, result);
2501         asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2502         CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
2503         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSTrash", JSTrashExecute,
2504             JSTrashCallbackComplete);
2505     }
2506     return result;
2507 }
2508 
JSIsTrashExecute(FileAssetAsyncContext * context)2509 static void JSIsTrashExecute(FileAssetAsyncContext* context)
2510 {
2511     MediaLibraryTracer tracer;
2512     tracer.Start("JSIsTrashExecute");
2513 
2514     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2515     context->isTrash = (context->objectPtr->GetIsTrash() != NOT_TRASH);
2516     return;
2517 }
2518 
JSIsTrashCallbackComplete(napi_env env,napi_status status,FileAssetAsyncContext * context)2519 static void JSIsTrashCallbackComplete(napi_env env, napi_status status,
2520                                       FileAssetAsyncContext* context)
2521 {
2522     MediaLibraryTracer tracer;
2523     tracer.Start("JSIsTrashCallbackComplete");
2524 
2525     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2526     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2527     CHECK_NULL_PTR_RETURN_VOID(jsContext, "jsContext context is null");
2528     jsContext->status = false;
2529     if (context->error == ERR_DEFAULT) {
2530         napi_get_boolean(env, context->isTrash, &jsContext->data);
2531         napi_get_undefined(env, &jsContext->error);
2532         jsContext->status = true;
2533     } else {
2534         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
2535             "UserFileClient is invalid");
2536         napi_get_undefined(env, &jsContext->data);
2537     }
2538 
2539     tracer.Finish();
2540     if (context->work != nullptr) {
2541         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2542                                                    context->work, *jsContext);
2543     }
2544 
2545     delete context;
2546 }
2547 
GetJSArgsForIsTrash(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)2548 static napi_value GetJSArgsForIsTrash(napi_env env, size_t argc, const napi_value argv[],
2549                                       FileAssetAsyncContext &asyncContext)
2550 {
2551     const int32_t refCount = 1;
2552     napi_value result;
2553     auto context = &asyncContext;
2554     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2555     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2556     for (size_t i = PARAM0; i < argc; i++) {
2557         napi_valuetype valueType = napi_undefined;
2558         napi_typeof(env, argv[i], &valueType);
2559         if (i == PARAM0 && valueType == napi_function) {
2560             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2561             break;
2562         } else {
2563             NAPI_ASSERT(env, false, "type mismatch");
2564         }
2565     }
2566     napi_get_boolean(env, true, &result);
2567     return result;
2568 }
2569 
JSIsTrash(napi_env env,napi_callback_info info)2570 napi_value FileAssetNapi::JSIsTrash(napi_env env, napi_callback_info info)
2571 {
2572     napi_status status;
2573     napi_value result = nullptr;
2574     size_t argc = ARGS_ONE;
2575     napi_value argv[ARGS_ONE] = {0};
2576     napi_value thisVar = nullptr;
2577     napi_value resource = nullptr;
2578 
2579     MediaLibraryTracer tracer;
2580     tracer.Start("JSIsTrash");
2581 
2582     GET_JS_ARGS(env, info, argc, argv, thisVar);
2583     NAPI_ASSERT(env, (argc == ARGS_ZERO || argc == ARGS_ONE), "requires 1 parameters maximum");
2584     napi_get_undefined(env, &result);
2585     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2586     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
2587     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2588     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2589         result = GetJSArgsForIsTrash(env, argc, argv, *asyncContext);
2590         ASSERT_NULLPTR_CHECK(env, result);
2591         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
2592         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSIsTrash", asyncContext);
2593         asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2594         CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
2595 
2596         status = napi_create_async_work(
2597             env, nullptr, resource, [](napi_env env, void *data) {
2598                 auto context = static_cast<FileAssetAsyncContext*>(data);
2599                 JSIsTrashExecute(context);
2600             },
2601             reinterpret_cast<CompleteCallback>(JSIsTrashCallbackComplete),
2602             static_cast<void *>(asyncContext.get()), &asyncContext->work);
2603         if (status != napi_ok) {
2604             napi_get_undefined(env, &result);
2605         } else {
2606             napi_queue_async_work(env, asyncContext->work);
2607             asyncContext.release();
2608         }
2609     }
2610 
2611     return result;
2612 }
2613 
UpdateFileAssetInfo()2614 void FileAssetNapi::UpdateFileAssetInfo()
2615 {
2616     fileAssetPtr = sFileAsset_;
2617 }
2618 
GetFileAssetInstance() const2619 shared_ptr<FileAsset> FileAssetNapi::GetFileAssetInstance() const
2620 {
2621     return fileAssetPtr;
2622 }
2623 
CheckSystemApiKeys(napi_env env,const string & key)2624 static int32_t CheckSystemApiKeys(napi_env env, const string &key)
2625 {
2626     static const set<string> SYSTEM_API_KEYS = {
2627         PhotoColumn::PHOTO_POSITION,
2628         MediaColumn::MEDIA_DATE_TRASHED,
2629         MediaColumn::MEDIA_HIDDEN,
2630         PhotoColumn::PHOTO_USER_COMMENT,
2631         PhotoColumn::CAMERA_SHOT_KEY,
2632         PENDING_STATUS,
2633     };
2634 
2635     if (SYSTEM_API_KEYS.find(key) != SYSTEM_API_KEYS.end() && !MediaLibraryNapiUtils::IsSystemApp()) {
2636         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This key can only be used by system apps");
2637         return E_CHECK_SYSTEMAPP_FAIL;
2638     }
2639     return E_SUCCESS;
2640 }
2641 
IsSpecialKey(const string & key)2642 static bool IsSpecialKey(const string &key)
2643 {
2644     static const set<string> SPECIAL_KEY = {
2645         PENDING_STATUS
2646     };
2647 
2648     if (SPECIAL_KEY.find(key) != SPECIAL_KEY.end()) {
2649         return true;
2650     }
2651     return false;
2652 }
2653 
HandleGettingSpecialKey(napi_env env,const string & key,const shared_ptr<FileAsset> & fileAssetPtr)2654 static napi_value HandleGettingSpecialKey(napi_env env, const string &key, const shared_ptr<FileAsset> &fileAssetPtr)
2655 {
2656     napi_value jsResult = nullptr;
2657     if (key == PENDING_STATUS) {
2658         if (fileAssetPtr->GetTimePending() == 0) {
2659             napi_get_boolean(env, false, &jsResult);
2660         } else {
2661             napi_get_boolean(env, true, &jsResult);
2662         }
2663     }
2664 
2665     return jsResult;
2666 }
2667 
GetCompatDate(const string inputKey,const int64_t date)2668 static inline int64_t GetCompatDate(const string inputKey, const int64_t date)
2669 {
2670     if (inputKey == MEDIA_DATA_DB_DATE_ADDED || inputKey == MEDIA_DATA_DB_DATE_MODIFIED ||
2671         inputKey == MEDIA_DATA_DB_DATE_TRASHED) {
2672             return date / MSEC_TO_SEC;
2673         }
2674     return date;
2675 }
2676 
UserFileMgrGet(napi_env env,napi_callback_info info)2677 napi_value FileAssetNapi::UserFileMgrGet(napi_env env, napi_callback_info info)
2678 {
2679     napi_value ret = nullptr;
2680     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2681     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
2682 
2683     string inputKey;
2684     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, asyncContext, inputKey),
2685         JS_ERR_PARAMETER_INVALID);
2686 
2687     if (CheckSystemApiKeys(env, inputKey) < 0) {
2688         return nullptr;
2689     }
2690 
2691     napi_value jsResult = nullptr;
2692     auto obj = asyncContext->objectInfo;
2693     napi_get_undefined(env, &jsResult);
2694     if (obj->fileAssetPtr->GetMemberMap().count(inputKey) == 0) {
2695         // no exist throw error
2696         NapiError::ThrowError(env, JS_E_FILE_KEY);
2697         return jsResult;
2698     }
2699 
2700     if (IsSpecialKey(inputKey)) {
2701         return HandleGettingSpecialKey(env, inputKey, obj->fileAssetPtr);
2702     }
2703     auto m = obj->fileAssetPtr->GetMemberMap().at(inputKey);
2704     if (m.index() == MEMBER_TYPE_STRING) {
2705         napi_create_string_utf8(env, get<string>(m).c_str(), NAPI_AUTO_LENGTH, &jsResult);
2706     } else if (m.index() == MEMBER_TYPE_INT32) {
2707         napi_create_int32(env, get<int32_t>(m), &jsResult);
2708     } else if (m.index() == MEMBER_TYPE_INT64) {
2709         napi_create_int64(env, GetCompatDate(inputKey, get<int64_t>(m)), &jsResult);
2710     } else {
2711         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
2712         return jsResult;
2713     }
2714     return jsResult;
2715 }
2716 
HandleParamSet(const string & inputKey,const string & value,ResultNapiType resultNapiType)2717 bool FileAssetNapi::HandleParamSet(const string &inputKey, const string &value, ResultNapiType resultNapiType)
2718 {
2719     if (resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
2720         if (inputKey == MediaColumn::MEDIA_TITLE) {
2721             fileAssetPtr->SetTitle(value);
2722         } else {
2723             NAPI_ERR_LOG("invalid key %{private}s, no support key", inputKey.c_str());
2724             return false;
2725         }
2726     } else if (resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
2727         if (inputKey == MediaColumn::MEDIA_NAME) {
2728             fileAssetPtr->SetDisplayName(value);
2729             fileAssetPtr->SetTitle(MediaFileUtils::GetTitleFromDisplayName(value));
2730         } else if (inputKey == MediaColumn::MEDIA_TITLE) {
2731             fileAssetPtr->SetTitle(value);
2732             string displayName = fileAssetPtr->GetDisplayName();
2733             if (!displayName.empty()) {
2734                 string extention = MediaFileUtils::SplitByChar(displayName, '.');
2735                 fileAssetPtr->SetDisplayName(value + "." + extention);
2736             }
2737         } else {
2738             NAPI_ERR_LOG("invalid key %{private}s, no support key", inputKey.c_str());
2739             return false;
2740         }
2741     } else {
2742         NAPI_ERR_LOG("invalid resultNapiType");
2743         return false;
2744     }
2745     return true;
2746 }
2747 
UserFileMgrSet(napi_env env,napi_callback_info info)2748 napi_value FileAssetNapi::UserFileMgrSet(napi_env env, napi_callback_info info)
2749 {
2750     MediaLibraryTracer tracer;
2751     tracer.Start("UserFileMgrSet");
2752 
2753     napi_value ret = nullptr;
2754     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2755     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
2756     string inputKey;
2757     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, asyncContext, inputKey),
2758         JS_ERR_PARAMETER_INVALID);
2759     string value;
2760     CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, asyncContext->argv[ARGS_ONE], value),
2761         JS_ERR_PARAMETER_INVALID);
2762     napi_value jsResult = nullptr;
2763     napi_get_undefined(env, &jsResult);
2764     auto obj = asyncContext->objectInfo;
2765     if (!obj->HandleParamSet(inputKey, value, obj->fileAssetPtr->GetResultNapiType())) {
2766         NapiError::ThrowError(env, JS_E_FILE_KEY);
2767         return jsResult;
2768     }
2769     return jsResult;
2770 }
2771 
UserFileMgrCommitModify(napi_env env,napi_callback_info info)2772 napi_value FileAssetNapi::UserFileMgrCommitModify(napi_env env, napi_callback_info info)
2773 {
2774     MediaLibraryTracer tracer;
2775     tracer.Start("UserFileMgrCommitModify");
2776 
2777     napi_value ret = nullptr;
2778     auto asyncContext = make_unique<FileAssetAsyncContext>();
2779     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
2780     NAPI_ASSERT(env, MediaLibraryNapiUtils::ParseArgsOnlyCallBack(env, info, asyncContext) == napi_ok,
2781         "Failed to parse js args");
2782     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2783     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "FileAsset is nullptr");
2784 
2785     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrCommitModify",
2786         JSCommitModifyExecute, JSCommitModifyCompleteCallback);
2787 }
2788 
UserFileMgrFavoriteComplete(napi_env env,napi_status status,void * data)2789 static void UserFileMgrFavoriteComplete(napi_env env, napi_status status, void *data)
2790 {
2791     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
2792     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2793     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2794     jsContext->status = false;
2795 
2796     if (context->error == ERR_DEFAULT) {
2797         napi_create_int32(env, context->changedRows, &jsContext->data);
2798         jsContext->status = true;
2799         napi_get_undefined(env, &jsContext->error);
2800     } else {
2801         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->changedRows,
2802             "Failed to modify favorite state");
2803         napi_get_undefined(env, &jsContext->data);
2804     }
2805 
2806     if (context->work != nullptr) {
2807         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2808             context->work, *jsContext);
2809     }
2810     delete context;
2811 }
2812 
UserFileMgrFavoriteExecute(napi_env env,void * data)2813 static void UserFileMgrFavoriteExecute(napi_env env, void *data)
2814 {
2815     MediaLibraryTracer tracer;
2816     tracer.Start("UserFileMgrFavoriteExecute");
2817 
2818     auto *context = static_cast<FileAssetAsyncContext *>(data);
2819 
2820     string uri;
2821     if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
2822         context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
2823         uri = UFM_UPDATE_PHOTO;
2824     } else if (context->objectPtr->GetMediaType() == MEDIA_TYPE_AUDIO) {
2825         uri = UFM_UPDATE_AUDIO;
2826     }
2827 
2828     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
2829     Uri updateAssetUri(uri);
2830     DataSharePredicates predicates;
2831     DataShareValuesBucket valuesBucket;
2832     int32_t changedRows;
2833     valuesBucket.Put(MediaColumn::MEDIA_IS_FAV, context->isFavorite ? IS_FAV : NOT_FAV);
2834     predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
2835     predicates.SetWhereArgs({ std::to_string(context->objectPtr->GetId()) });
2836 
2837     changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
2838     if (changedRows < 0) {
2839         context->SaveError(changedRows);
2840         NAPI_ERR_LOG("Failed to modify favorite state, err: %{public}d", changedRows);
2841     } else {
2842         context->objectPtr->SetFavorite(context->isFavorite);
2843         context->changedRows = changedRows;
2844     }
2845 }
2846 
UserFileMgrFavorite(napi_env env,napi_callback_info info)2847 napi_value FileAssetNapi::UserFileMgrFavorite(napi_env env, napi_callback_info info)
2848 {
2849     auto asyncContext = make_unique<FileAssetAsyncContext>();
2850     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
2851     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsBoolCallBack(env, info, asyncContext, asyncContext->isFavorite),
2852         JS_ERR_PARAMETER_INVALID);
2853     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2854     CHECK_NULLPTR_RET(asyncContext->objectPtr);
2855 
2856     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrFavorite",
2857         UserFileMgrFavoriteExecute, UserFileMgrFavoriteComplete);
2858 }
UserFileMgrGetThumbnail(napi_env env,napi_callback_info info)2859 napi_value FileAssetNapi::UserFileMgrGetThumbnail(napi_env env, napi_callback_info info)
2860 {
2861     MediaLibraryTracer tracer;
2862     tracer.Start("UserFileMgrGetThumbnail");
2863 
2864     auto asyncContext = make_unique<FileAssetAsyncContext>();
2865     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_ZERO, ARGS_TWO),
2866         JS_INNER_FAIL);
2867     CHECK_NULLPTR_RET(GetJSArgsForGetThumbnail(env, asyncContext->argc, asyncContext->argv, asyncContext));
2868 
2869     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2870     CHECK_NULLPTR_RET(asyncContext->objectPtr);
2871     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
2872 
2873     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrGetThumbnail",
2874         [](napi_env env, void *data) {
2875             auto context = static_cast<FileAssetAsyncContext*>(data);
2876             JSGetThumbnailExecute(context);
2877         },
2878         reinterpret_cast<CompleteCallback>(JSGetThumbnailCompleteCallback));
2879 }
2880 
ParseArgsUserFileMgrOpen(napi_env env,napi_callback_info info,unique_ptr<FileAssetAsyncContext> & context,bool isReadOnly)2881 static napi_value ParseArgsUserFileMgrOpen(napi_env env, napi_callback_info info,
2882     unique_ptr<FileAssetAsyncContext> &context, bool isReadOnly)
2883 {
2884     if (!isReadOnly && !MediaLibraryNapiUtils::IsSystemApp()) {
2885         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
2886         return nullptr;
2887     }
2888 
2889     size_t minArgs = ARGS_ZERO;
2890     size_t maxArgs = ARGS_ONE;
2891     if (!isReadOnly) {
2892         minArgs++;
2893         maxArgs++;
2894     }
2895     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
2896         JS_ERR_PARAMETER_INVALID);
2897     auto fileUri = context->objectInfo->GetFileUri();
2898     MediaLibraryNapiUtils::UriAppendKeyValue(fileUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
2899     context->valuesBucket.Put(MEDIA_DATA_DB_URI, fileUri);
2900 
2901     if (isReadOnly) {
2902         context->valuesBucket.Put(MEDIA_FILEMODE, MEDIA_FILEMODE_READONLY);
2903     } else {
2904         string mode;
2905         CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[PARAM0], mode),
2906             JS_ERR_PARAMETER_INVALID);
2907         transform(mode.begin(), mode.end(), mode.begin(), ::tolower);
2908         if (!MediaFileUtils::CheckMode(mode)) {
2909             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
2910             return nullptr;
2911         }
2912         context->valuesBucket.Put(MEDIA_FILEMODE, mode);
2913     }
2914 
2915     napi_value result = nullptr;
2916     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
2917     return result;
2918 }
2919 
UserFileMgrOpenExecute(napi_env env,void * data)2920 static void UserFileMgrOpenExecute(napi_env env, void *data)
2921 {
2922     MediaLibraryTracer tracer;
2923     tracer.Start("JSOpenExecute");
2924 
2925     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
2926     bool isValid = false;
2927     string mode = context->valuesBucket.Get(MEDIA_FILEMODE, isValid);
2928     if (!isValid) {
2929         context->SaveError(-EINVAL);
2930         return;
2931     }
2932     string fileUri = context->valuesBucket.Get(MEDIA_DATA_DB_URI, isValid);
2933     if (!isValid) {
2934         context->SaveError(-EINVAL);
2935         return ;
2936     }
2937 
2938     MediaFileUtils::UriAppendKeyValue(fileUri, MediaColumn::MEDIA_TIME_PENDING,
2939         to_string(context->objectPtr->GetTimePending()));
2940     Uri openFileUri(fileUri);
2941     int32_t retVal = UserFileClient::OpenFile(openFileUri, mode);
2942     if (retVal <= 0) {
2943         context->SaveError(retVal);
2944         NAPI_ERR_LOG("File open asset failed, ret: %{public}d", retVal);
2945     } else {
2946         context->fd = retVal;
2947         if (mode.find('w') != string::npos) {
2948             context->objectPtr->SetOpenStatus(retVal, OPEN_TYPE_WRITE);
2949         } else {
2950             context->objectPtr->SetOpenStatus(retVal, OPEN_TYPE_READONLY);
2951         }
2952         if (context->objectPtr->GetTimePending() == UNCREATE_FILE_TIMEPENDING) {
2953             context->objectPtr->SetTimePending(UNCLOSE_FILE_TIMEPENDING);
2954         }
2955     }
2956 }
2957 
UserFileMgrOpenCallbackComplete(napi_env env,napi_status status,void * data)2958 static void UserFileMgrOpenCallbackComplete(napi_env env, napi_status status, void *data)
2959 {
2960     MediaLibraryTracer tracer;
2961     tracer.Start("UserFileMgrOpenCallbackComplete");
2962 
2963     auto *context = static_cast<FileAssetAsyncContext *>(data);
2964     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2965 
2966     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2967     jsContext->status = false;
2968 
2969     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
2970     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
2971     if (context->error == ERR_DEFAULT) {
2972         CHECK_ARGS_RET_VOID(env, napi_create_int32(env, context->fd, &jsContext->data), JS_INNER_FAIL);
2973         jsContext->status = true;
2974     } else {
2975         context->HandleError(env, jsContext->error);
2976     }
2977 
2978     tracer.Finish();
2979     if (context->work != nullptr) {
2980         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2981                                                    context->work, *jsContext);
2982     }
2983     delete context;
2984 }
2985 
JSGetAnalysisDataCompleteCallback(napi_env env,napi_status status,void * data)2986 static void JSGetAnalysisDataCompleteCallback(napi_env env, napi_status status, void *data)
2987 {
2988     MediaLibraryTracer tracer;
2989     tracer.Start("JSGetAnalysisDataCompleteCallback");
2990 
2991     auto *context = static_cast<FileAssetAsyncContext *>(data);
2992     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2993 
2994     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2995     jsContext->status = false;
2996 
2997     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
2998     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
2999     if (context->error == ERR_DEFAULT) {
3000         CHECK_ARGS_RET_VOID(env, napi_create_string_utf8(env, context->analysisData.c_str(),
3001             NAPI_AUTO_LENGTH, &jsContext->data), JS_INNER_FAIL);
3002         jsContext->status = true;
3003     } else {
3004         context->HandleError(env, jsContext->error);
3005     }
3006 
3007     tracer.Finish();
3008     if (context->work != nullptr) {
3009         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3010                                                    context->work, *jsContext);
3011     }
3012     delete context;
3013 }
3014 
UserFileMgrOpen(napi_env env,napi_callback_info info)3015 napi_value FileAssetNapi::UserFileMgrOpen(napi_env env, napi_callback_info info)
3016 {
3017     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3018     CHECK_NULLPTR_RET(ParseArgsUserFileMgrOpen(env, info, asyncContext, false));
3019     if (asyncContext->objectInfo->fileAssetPtr == nullptr) {
3020         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3021         return nullptr;
3022     }
3023     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3024 
3025     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrOpen",
3026         UserFileMgrOpenExecute, UserFileMgrOpenCallbackComplete);
3027 }
3028 
JSGetReadOnlyFd(napi_env env,napi_callback_info info)3029 napi_value FileAssetNapi::JSGetReadOnlyFd(napi_env env, napi_callback_info info)
3030 {
3031     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3032     CHECK_NULLPTR_RET(ParseArgsUserFileMgrOpen(env, info, asyncContext, true));
3033     if (asyncContext->objectInfo->fileAssetPtr == nullptr) {
3034         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3035         return nullptr;
3036     }
3037     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3038 
3039     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets", UserFileMgrOpenExecute,
3040         UserFileMgrOpenCallbackComplete);
3041 }
3042 
ParseArgsUserFileMgrClose(napi_env env,napi_callback_info info,unique_ptr<FileAssetAsyncContext> & context)3043 static napi_value ParseArgsUserFileMgrClose(napi_env env, napi_callback_info info,
3044     unique_ptr<FileAssetAsyncContext> &context)
3045 {
3046     size_t minArgs = ARGS_ONE;
3047     size_t maxArgs = ARGS_TWO;
3048     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
3049         JS_ERR_PARAMETER_INVALID);
3050     context->valuesBucket.Put(MEDIA_DATA_DB_URI, context->objectInfo->GetFileUri());
3051 
3052     int32_t fd = 0;
3053     CHECK_COND(env, MediaLibraryNapiUtils::GetInt32Arg(env, context->argv[PARAM0], fd), JS_ERR_PARAMETER_INVALID);
3054     if (fd <= 0) {
3055         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3056         return nullptr;
3057     }
3058     context->fd = fd;
3059 
3060     napi_value result = nullptr;
3061     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
3062     return result;
3063 }
3064 
UserFileMgrCloseExecute(napi_env env,void * data)3065 static void UserFileMgrCloseExecute(napi_env env, void *data)
3066 {
3067     MediaLibraryTracer tracer;
3068     tracer.Start("UserFileMgrCloseExecute");
3069 
3070     auto *context = static_cast<FileAssetAsyncContext*>(data);
3071     UniqueFd unifd(context->fd);
3072     if (!CheckFileOpenStatus(context, unifd.Get())) {
3073         return;
3074     }
3075     string closeUri;
3076     if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
3077         context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
3078         closeUri = UFM_CLOSE_PHOTO;
3079     } else if (context->objectPtr->GetMediaType() == MEDIA_TYPE_AUDIO) {
3080         closeUri = UFM_CLOSE_AUDIO;
3081     } else {
3082         context->SaveError(-EINVAL);
3083         return;
3084     }
3085     MediaLibraryNapiUtils::UriAppendKeyValue(closeUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3086     MediaLibraryNapiUtils::UriAppendKeyValue(closeUri, MediaColumn::MEDIA_TIME_PENDING,
3087         to_string(context->objectPtr->GetTimePending()));
3088     Uri closeAssetUri(closeUri);
3089     int32_t ret = UserFileClient::Insert(closeAssetUri, context->valuesBucket);
3090     if (ret != E_SUCCESS) {
3091         context->SaveError(ret);
3092     } else {
3093         if (context->objectPtr->GetTimePending() == UNCLOSE_FILE_TIMEPENDING) {
3094             context->objectPtr->SetTimePending(0);
3095         }
3096     }
3097 }
3098 
UserFileMgrCloseCallbackComplete(napi_env env,napi_status status,void * data)3099 static void UserFileMgrCloseCallbackComplete(napi_env env, napi_status status, void *data)
3100 {
3101     MediaLibraryTracer tracer;
3102     tracer.Start("UserFileMgrCloseCallbackComplete");
3103 
3104     auto context = static_cast<FileAssetAsyncContext *>(data);
3105     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3106 
3107     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3108     jsContext->status = false;
3109 
3110     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
3111     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
3112     if (context->error == ERR_DEFAULT) {
3113         CHECK_ARGS_RET_VOID(env, napi_create_int32(env, E_SUCCESS, &jsContext->data), JS_INNER_FAIL);
3114         jsContext->status = true;
3115     } else {
3116         context->HandleError(env, jsContext->error);
3117     }
3118 
3119     tracer.Finish();
3120     if (context->work != nullptr) {
3121         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3122                                                    context->work, *jsContext);
3123     }
3124     delete context;
3125 }
3126 
UserFileMgrClose(napi_env env,napi_callback_info info)3127 napi_value FileAssetNapi::UserFileMgrClose(napi_env env, napi_callback_info info)
3128 {
3129     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3130     CHECK_NULLPTR_RET(ParseArgsUserFileMgrClose(env, info, asyncContext));
3131     if (asyncContext->objectInfo->fileAssetPtr == nullptr) {
3132         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3133         return nullptr;
3134     }
3135     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3136 
3137     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets", UserFileMgrCloseExecute,
3138         UserFileMgrCloseCallbackComplete);
3139 }
3140 
UserFileMgrSetHiddenExecute(napi_env env,void * data)3141 static void UserFileMgrSetHiddenExecute(napi_env env, void *data)
3142 {
3143     MediaLibraryTracer tracer;
3144     tracer.Start("UserFileMgrSetHiddenExecute");
3145 
3146     auto *context = static_cast<FileAssetAsyncContext *>(data);
3147     if (context->objectPtr->GetMediaType() != MEDIA_TYPE_IMAGE &&
3148         context->objectPtr->GetMediaType() != MEDIA_TYPE_VIDEO) {
3149         context->SaveError(-EINVAL);
3150         return;
3151     }
3152 
3153     string uri = UFM_HIDE_PHOTO;
3154     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3155     Uri updateAssetUri(uri);
3156     DataSharePredicates predicates;
3157     predicates.In(MediaColumn::MEDIA_ID, vector<string>({ context->objectPtr->GetUri() }));
3158     DataShareValuesBucket valuesBucket;
3159     valuesBucket.Put(MediaColumn::MEDIA_HIDDEN, context->isHidden ? IS_HIDDEN : NOT_HIDDEN);
3160 
3161     int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
3162     if (changedRows < 0) {
3163         context->SaveError(changedRows);
3164         NAPI_ERR_LOG("Failed to modify hidden state, err: %{public}d", changedRows);
3165     } else {
3166         context->objectPtr->SetHidden(context->isHidden);
3167         context->changedRows = changedRows;
3168     }
3169 }
3170 
UserFileMgrSetHiddenComplete(napi_env env,napi_status status,void * data)3171 static void UserFileMgrSetHiddenComplete(napi_env env, napi_status status, void *data)
3172 {
3173     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
3174     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3175     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3176     jsContext->status = false;
3177 
3178     if (context->error == ERR_DEFAULT) {
3179         napi_create_int32(env, context->changedRows, &jsContext->data);
3180         jsContext->status = true;
3181         napi_get_undefined(env, &jsContext->error);
3182     } else {
3183         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->changedRows,
3184             "Failed to modify hidden state");
3185         napi_get_undefined(env, &jsContext->data);
3186     }
3187 
3188     if (context->work != nullptr) {
3189         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3190             context->work, *jsContext);
3191     }
3192     delete context;
3193 }
3194 
UserFileMgrSetHidden(napi_env env,napi_callback_info info)3195 napi_value FileAssetNapi::UserFileMgrSetHidden(napi_env env, napi_callback_info info)
3196 {
3197     MediaLibraryTracer tracer;
3198     tracer.Start("UserFileMgrSetHidden");
3199 
3200     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3201     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
3202     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsBoolCallBack(env, info, asyncContext, asyncContext->isHidden),
3203         JS_ERR_PARAMETER_INVALID);
3204     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3205     CHECK_NULLPTR_RET(asyncContext->objectPtr);
3206 
3207     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrSetHidden",
3208         UserFileMgrSetHiddenExecute, UserFileMgrSetHiddenComplete);
3209 }
3210 
UserFileMgrSetPendingExecute(napi_env env,void * data)3211 static void UserFileMgrSetPendingExecute(napi_env env, void *data)
3212 {
3213     MediaLibraryTracer tracer;
3214     tracer.Start("UserFileMgrSetPendingExecute");
3215     auto *context = static_cast<FileAssetAsyncContext*>(data);
3216 
3217     string uri = MEDIALIBRARY_DATA_URI + "/";
3218     if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
3219         context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
3220         uri += UFM_PHOTO + "/" + OPRN_PENDING;
3221     } else if (context->objectPtr->GetMediaType() == MEDIA_TYPE_AUDIO) {
3222         uri += UFM_AUDIO + "/" + OPRN_PENDING;
3223     } else {
3224         context->error = OHOS_INVALID_PARAM_CODE;
3225         return;
3226     }
3227 
3228     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3229     Uri updateAssetUri(uri);
3230     DataSharePredicates predicates;
3231     DataShareValuesBucket valuesBucket;
3232     int32_t changedRows;
3233     valuesBucket.Put(MediaColumn::MEDIA_TIME_PENDING, context->isPending ? 1 : 0);
3234     predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
3235     predicates.SetWhereArgs({ std::to_string(context->objectPtr->GetId()) });
3236 
3237     changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
3238     if (changedRows < 0) {
3239         context->SaveError(E_FAIL);
3240         NAPI_ERR_LOG("Failed to modify pending state, err: %{public}d", changedRows);
3241     } else {
3242         context->changedRows = changedRows;
3243         context->objectPtr->SetTimePending((context->isPending) ? 1 : 0);
3244     }
3245 }
3246 
UserFileMgrSetPendingComplete(napi_env env,napi_status status,void * data)3247 static void UserFileMgrSetPendingComplete(napi_env env, napi_status status, void *data)
3248 {
3249     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
3250     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3251     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3252     jsContext->status = false;
3253 
3254     if (context->error == ERR_DEFAULT) {
3255         napi_create_int32(env, context->changedRows, &jsContext->data);
3256         jsContext->status = true;
3257         napi_get_undefined(env, &jsContext->error);
3258     } else {
3259         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->changedRows,
3260             "Failed to modify pending state");
3261         napi_get_undefined(env, &jsContext->data);
3262     }
3263 
3264     if (context->work != nullptr) {
3265         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3266             context->work, *jsContext);
3267     }
3268     delete context;
3269 }
3270 
UserFileMgrSetPending(napi_env env,napi_callback_info info)3271 napi_value FileAssetNapi::UserFileMgrSetPending(napi_env env, napi_callback_info info)
3272 {
3273     MediaLibraryTracer tracer;
3274     tracer.Start("UserFileMgrSetPending");
3275 
3276     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3277     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
3278     CHECK_ARGS_THROW_INVALID_PARAM(env,
3279         MediaLibraryNapiUtils::ParseArgsBoolCallBack(env, info, asyncContext, asyncContext->isPending));
3280     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3281     CHECK_NULLPTR_RET(asyncContext->objectPtr);
3282 
3283     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrSetPending",
3284         UserFileMgrSetPendingExecute, UserFileMgrSetPendingComplete);
3285 }
3286 
UserFileMgrGetExifExecute(napi_env env,void * data)3287 static void UserFileMgrGetExifExecute(napi_env env, void *data) {}
3288 
CheckNapiCallerPermission(const std::string & permission)3289 static bool CheckNapiCallerPermission(const std::string &permission)
3290 {
3291     MediaLibraryTracer tracer;
3292     tracer.Start("CheckNapiCallerPermission");
3293 
3294     AccessTokenID tokenCaller = IPCSkeleton::GetSelfTokenID();
3295     int res = AccessTokenKit::VerifyAccessToken(tokenCaller, permission);
3296     if (res != PermissionState::PERMISSION_GRANTED) {
3297         NAPI_ERR_LOG("Have no media permission: %{public}s", permission.c_str());
3298         return false;
3299     }
3300 
3301     return true;
3302 }
3303 
UserFileMgrGetExifComplete(napi_env env,napi_status status,void * data)3304 static void UserFileMgrGetExifComplete(napi_env env, napi_status status, void *data)
3305 {
3306     auto *context = static_cast<FileAssetAsyncContext*>(data);
3307     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3308     auto jsContext = make_unique<JSAsyncContextOutput>();
3309     jsContext->status = false;
3310 
3311     auto *obj = context->objectInfo;
3312     nlohmann::json allExifJson;
3313     if (!obj->GetAllExif().empty()) {
3314         allExifJson = nlohmann::json::parse(obj->GetAllExif());
3315     }
3316     if (allExifJson.is_discarded() || obj->GetAllExif().empty()) {
3317         NAPI_ERR_LOG("parse json failed");
3318         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, JS_INNER_FAIL,
3319             "parse json failed");
3320         napi_get_undefined(env, &jsContext->data);
3321     } else {
3322         const std::string PERMISSION_NAME_MEDIA_LOCATION = "ohos.permission.MEDIA_LOCATION";
3323         auto err = CheckNapiCallerPermission(PERMISSION_NAME_MEDIA_LOCATION);
3324         if (err == false) {
3325             allExifJson.erase(PHOTO_DATA_IMAGE_GPS_LATITUDE);
3326             allExifJson.erase(PHOTO_DATA_IMAGE_GPS_LONGITUDE);
3327             allExifJson.erase(PHOTO_DATA_IMAGE_GPS_LATITUDE_REF);
3328             allExifJson.erase(PHOTO_DATA_IMAGE_GPS_LONGITUDE_REF);
3329         }
3330         allExifJson[PHOTO_DATA_IMAGE_USER_COMMENT] = obj->GetUserComment();
3331         allExifJson[PHOTO_DATA_IMAGE_IMAGE_DESCRIPTION] =
3332             AppFileService::SandboxHelper::Decode(allExifJson[PHOTO_DATA_IMAGE_IMAGE_DESCRIPTION]);
3333         napi_create_string_utf8(env, allExifJson.dump().c_str(), NAPI_AUTO_LENGTH, &jsContext->data);
3334         jsContext->status = true;
3335         napi_get_undefined(env, &jsContext->error);
3336     }
3337 
3338     if (context->work != nullptr) {
3339         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3340             context->work, *jsContext);
3341     }
3342     delete context;
3343 }
3344 
JSGetExif(napi_env env,napi_callback_info info)3345 napi_value FileAssetNapi::JSGetExif(napi_env env, napi_callback_info info)
3346 {
3347     MediaLibraryTracer tracer;
3348     tracer.Start("JSGetExif");
3349 
3350     if (!MediaLibraryNapiUtils::IsSystemApp()) {
3351         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
3352         return nullptr;
3353     }
3354 
3355     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3356     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_ZERO, ARGS_ONE),
3357         JS_ERR_PARAMETER_INVALID);
3358     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3359     CHECK_NULLPTR_RET(asyncContext->objectPtr);
3360 
3361     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetExif", UserFileMgrGetExifExecute,
3362         UserFileMgrGetExifComplete);
3363 }
3364 
UserFileMgrSetUserCommentComplete(napi_env env,napi_status status,void * data)3365 static void UserFileMgrSetUserCommentComplete(napi_env env, napi_status status, void *data)
3366 {
3367     auto *context = static_cast<FileAssetAsyncContext*>(data);
3368     auto jsContext = make_unique<JSAsyncContextOutput>();
3369     jsContext->status = false;
3370 
3371     if (context->error == ERR_DEFAULT) {
3372         napi_create_int32(env, context->changedRows, &jsContext->data);
3373         jsContext->status = true;
3374         napi_get_undefined(env, &jsContext->error);
3375     } else {
3376         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
3377             "Failed to edit user comment");
3378         napi_get_undefined(env, &jsContext->data);
3379     }
3380 
3381     if (context->work != nullptr) {
3382         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3383             context->work, *jsContext);
3384     }
3385     delete context;
3386 }
3387 
UserFileMgrSetUserCommentExecute(napi_env env,void * data)3388 static void UserFileMgrSetUserCommentExecute(napi_env env, void *data)
3389 {
3390     MediaLibraryTracer tracer;
3391     tracer.Start("UserFileMgrSetUserCommentExecute");
3392 
3393     auto *context = static_cast<FileAssetAsyncContext *>(data);
3394     string uri = UFM_SET_USER_COMMENT;
3395     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3396     Uri editUserCommentUri(uri);
3397     DataSharePredicates predicates;
3398     DataShareValuesBucket valuesBucket;
3399     valuesBucket.Put(PhotoColumn::PHOTO_USER_COMMENT, context->userComment);
3400     predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
3401     predicates.SetWhereArgs({std::to_string(context->objectPtr->GetId())});
3402     int32_t changedRows = UserFileClient::Update(editUserCommentUri, predicates, valuesBucket);
3403     if (changedRows < 0) {
3404         context->SaveError(changedRows);
3405         NAPI_ERR_LOG("Failed to modify user comment, err: %{public}d", changedRows);
3406     } else {
3407         context->objectPtr->SetUserComment(context->userComment);
3408         context->changedRows = changedRows;
3409     }
3410 }
3411 
UserFileMgrSetUserComment(napi_env env,napi_callback_info info)3412 napi_value FileAssetNapi::UserFileMgrSetUserComment(napi_env env, napi_callback_info info)
3413 {
3414     MediaLibraryTracer tracer;
3415     tracer.Start("UserFileMgrSetUserComment");
3416 
3417     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3418     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
3419     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, asyncContext, asyncContext->userComment),
3420         JS_ERR_PARAMETER_INVALID);
3421     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3422     if (asyncContext->objectPtr == nullptr) {
3423         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3424         return nullptr;
3425     }
3426 
3427     if (asyncContext->userComment.length() > USER_COMMENT_MAX_LEN) {
3428         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "user comment too long");
3429         return nullptr;
3430     }
3431 
3432     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrSetUserComment",
3433         UserFileMgrSetUserCommentExecute, UserFileMgrSetUserCommentComplete);
3434 }
3435 
ParseArgsPhotoAccessHelperOpen(napi_env env,napi_callback_info info,unique_ptr<FileAssetAsyncContext> & context,bool isReadOnly)3436 static napi_value ParseArgsPhotoAccessHelperOpen(napi_env env, napi_callback_info info,
3437     unique_ptr<FileAssetAsyncContext> &context, bool isReadOnly)
3438 {
3439     if (!isReadOnly && !MediaLibraryNapiUtils::IsSystemApp()) {
3440         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
3441         return nullptr;
3442     }
3443     size_t minArgs = ARGS_ZERO;
3444     size_t maxArgs = ARGS_ONE;
3445     if (!isReadOnly) {
3446         minArgs++;
3447         maxArgs++;
3448     }
3449     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
3450         JS_ERR_PARAMETER_INVALID);
3451     auto fileUri = context->objectInfo->GetFileUri();
3452     MediaLibraryNapiUtils::UriAppendKeyValue(fileUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3453     context->valuesBucket.Put(MEDIA_DATA_DB_URI, fileUri);
3454 
3455     if (isReadOnly) {
3456         context->valuesBucket.Put(MEDIA_FILEMODE, MEDIA_FILEMODE_READONLY);
3457     } else {
3458         string mode;
3459         CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[PARAM0], mode),
3460             JS_ERR_PARAMETER_INVALID);
3461         transform(mode.begin(), mode.end(), mode.begin(), ::tolower);
3462         if (!MediaFileUtils::CheckMode(mode)) {
3463             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3464             return nullptr;
3465         }
3466         context->valuesBucket.Put(MEDIA_FILEMODE, mode);
3467     }
3468 
3469     napi_value result = nullptr;
3470     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
3471     return result;
3472 }
3473 
PhotoAccessHelperOpenExecute(napi_env env,void * data)3474 static void PhotoAccessHelperOpenExecute(napi_env env, void *data)
3475 {
3476     MediaLibraryTracer tracer;
3477     tracer.Start("PhotoAccessHelperOpenExecute");
3478 
3479     auto *context = static_cast<FileAssetAsyncContext*>(data);
3480     bool isValid = false;
3481     string mode = context->valuesBucket.Get(MEDIA_FILEMODE, isValid);
3482     if (!isValid) {
3483         context->SaveError(-EINVAL);
3484         return;
3485     }
3486     string fileUri = context->valuesBucket.Get(MEDIA_DATA_DB_URI, isValid);
3487     if (!isValid) {
3488         context->SaveError(-EINVAL);
3489         return ;
3490     }
3491 
3492     if (context->objectPtr->GetTimePending() == UNCREATE_FILE_TIMEPENDING) {
3493         MediaFileUtils::UriAppendKeyValue(fileUri, MediaColumn::MEDIA_TIME_PENDING,
3494             to_string(context->objectPtr->GetTimePending()));
3495     }
3496     Uri openFileUri(fileUri);
3497     int32_t retVal = UserFileClient::OpenFile(openFileUri, mode);
3498     if (retVal <= 0) {
3499         context->SaveError(retVal);
3500         NAPI_ERR_LOG("File open asset failed, ret: %{public}d", retVal);
3501     } else {
3502         context->fd = retVal;
3503         if (mode.find('w') != string::npos) {
3504             context->objectPtr->SetOpenStatus(retVal, OPEN_TYPE_WRITE);
3505         } else {
3506             context->objectPtr->SetOpenStatus(retVal, OPEN_TYPE_READONLY);
3507         }
3508         if (context->objectPtr->GetTimePending() == UNCREATE_FILE_TIMEPENDING) {
3509             context->objectPtr->SetTimePending(UNCLOSE_FILE_TIMEPENDING);
3510         }
3511     }
3512 }
3513 
PhotoAccessHelperOpenCallbackComplete(napi_env env,napi_status status,void * data)3514 static void PhotoAccessHelperOpenCallbackComplete(napi_env env, napi_status status, void *data)
3515 {
3516     MediaLibraryTracer tracer;
3517     tracer.Start("PhotoAccessHelperOpenCallbackComplete");
3518 
3519     auto context = static_cast<FileAssetAsyncContext *>(data);
3520     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3521 
3522     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3523     jsContext->status = false;
3524 
3525     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
3526     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
3527     if (context->error == ERR_DEFAULT) {
3528         CHECK_ARGS_RET_VOID(env, napi_create_int32(env, context->fd, &jsContext->data), JS_INNER_FAIL);
3529         jsContext->status = true;
3530     } else {
3531         context->HandleError(env, jsContext->error);
3532     }
3533 
3534     tracer.Finish();
3535     if (context->work != nullptr) {
3536         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3537                                                    context->work, *jsContext);
3538     }
3539     delete context;
3540 }
3541 
PhotoAccessHelperOpen(napi_env env,napi_callback_info info)3542 napi_value FileAssetNapi::PhotoAccessHelperOpen(napi_env env, napi_callback_info info)
3543 {
3544     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3545     CHECK_NULLPTR_RET(ParseArgsPhotoAccessHelperOpen(env, info, asyncContext, false));
3546     if (asyncContext->objectInfo->fileAssetPtr == nullptr) {
3547         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3548         return nullptr;
3549     }
3550     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3551 
3552     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperOpen",
3553         PhotoAccessHelperOpenExecute, PhotoAccessHelperOpenCallbackComplete);
3554 }
3555 
ParseArgsPhotoAccessHelperClose(napi_env env,napi_callback_info info,unique_ptr<FileAssetAsyncContext> & context)3556 static napi_value ParseArgsPhotoAccessHelperClose(napi_env env, napi_callback_info info,
3557     unique_ptr<FileAssetAsyncContext> &context)
3558 {
3559     size_t minArgs = ARGS_ONE;
3560     size_t maxArgs = ARGS_TWO;
3561     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
3562         JS_ERR_PARAMETER_INVALID);
3563     context->valuesBucket.Put(MEDIA_DATA_DB_URI, context->objectInfo->GetFileUri());
3564 
3565     int32_t fd = 0;
3566     CHECK_COND(env, MediaLibraryNapiUtils::GetInt32Arg(env, context->argv[PARAM0], fd), JS_ERR_PARAMETER_INVALID);
3567     if (fd <= 0) {
3568         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3569         return nullptr;
3570     }
3571     context->fd = fd;
3572 
3573     napi_value result = nullptr;
3574     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
3575     return result;
3576 }
3577 
PhotoAccessHelperCloseExecute(napi_env env,void * data)3578 static void PhotoAccessHelperCloseExecute(napi_env env, void *data)
3579 {
3580     MediaLibraryTracer tracer;
3581     tracer.Start("PhotoAccessHelperCloseExecute");
3582 
3583     auto *context = static_cast<FileAssetAsyncContext*>(data);
3584     UniqueFd unifd(context->fd);
3585     if (!CheckFileOpenStatus(context, unifd.Get())) {
3586         return;
3587     }
3588     string closeUri;
3589     if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
3590         context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
3591         closeUri = PAH_CLOSE_PHOTO;
3592     } else {
3593         context->SaveError(-EINVAL);
3594         return;
3595     }
3596     MediaLibraryNapiUtils::UriAppendKeyValue(closeUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3597     MediaLibraryNapiUtils::UriAppendKeyValue(closeUri, MediaColumn::MEDIA_TIME_PENDING,
3598         to_string(context->objectPtr->GetTimePending()));
3599     Uri closeAssetUri(closeUri);
3600     int32_t ret = UserFileClient::Insert(closeAssetUri, context->valuesBucket);
3601     if (ret != E_SUCCESS) {
3602         context->SaveError(ret);
3603     } else {
3604         if (context->objectPtr->GetTimePending() == UNCLOSE_FILE_TIMEPENDING) {
3605             context->objectPtr->SetTimePending(0);
3606         }
3607     }
3608 }
3609 
PhotoAccessHelperCloseCallbackComplete(napi_env env,napi_status status,void * data)3610 static void PhotoAccessHelperCloseCallbackComplete(napi_env env, napi_status status, void *data)
3611 {
3612     MediaLibraryTracer tracer;
3613     tracer.Start("PhotoAccessHelperCloseCallbackComplete");
3614 
3615     auto context = static_cast<FileAssetAsyncContext *>(data);
3616     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3617 
3618     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3619     jsContext->status = false;
3620 
3621     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
3622     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
3623     if (context->error == ERR_DEFAULT) {
3624         CHECK_ARGS_RET_VOID(env, napi_create_int32(env, E_SUCCESS, &jsContext->data), JS_INNER_FAIL);
3625         jsContext->status = true;
3626     } else {
3627         context->HandleError(env, jsContext->error);
3628     }
3629 
3630     tracer.Finish();
3631     if (context->work != nullptr) {
3632         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3633                                                    context->work, *jsContext);
3634     }
3635     delete context;
3636 }
3637 
PhotoAccessHelperClose(napi_env env,napi_callback_info info)3638 napi_value FileAssetNapi::PhotoAccessHelperClose(napi_env env, napi_callback_info info)
3639 {
3640     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3641     CHECK_NULLPTR_RET(ParseArgsPhotoAccessHelperClose(env, info, asyncContext));
3642     if (asyncContext->objectInfo->fileAssetPtr == nullptr) {
3643         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3644         return nullptr;
3645     }
3646     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3647 
3648     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperClose",
3649         PhotoAccessHelperCloseExecute, PhotoAccessHelperCloseCallbackComplete);
3650 }
3651 
PhotoAccessHelperCommitModify(napi_env env,napi_callback_info info)3652 napi_value FileAssetNapi::PhotoAccessHelperCommitModify(napi_env env, napi_callback_info info)
3653 {
3654     MediaLibraryTracer tracer;
3655     tracer.Start("PhotoAccessHelperCommitModify");
3656 
3657     napi_value ret = nullptr;
3658     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3659     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
3660     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
3661     NAPI_ASSERT(env, MediaLibraryNapiUtils::ParseArgsOnlyCallBack(env, info, asyncContext) == napi_ok,
3662         "Failed to parse js args");
3663     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3664     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "FileAsset is nullptr");
3665 
3666     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperCommitModify",
3667         JSCommitModifyExecute, JSCommitModifyCompleteCallback);
3668 }
3669 
PhotoAccessHelperFavoriteComplete(napi_env env,napi_status status,void * data)3670 static void PhotoAccessHelperFavoriteComplete(napi_env env, napi_status status, void *data)
3671 {
3672     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
3673     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3674     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3675     jsContext->status = false;
3676 
3677     if (context->error == ERR_DEFAULT) {
3678         napi_create_int32(env, context->changedRows, &jsContext->data);
3679         jsContext->status = true;
3680         napi_get_undefined(env, &jsContext->error);
3681     } else {
3682         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->changedRows,
3683             "Failed to modify favorite state");
3684         napi_get_undefined(env, &jsContext->data);
3685     }
3686 
3687     if (context->work != nullptr) {
3688         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3689             context->work, *jsContext);
3690     }
3691     delete context;
3692 }
3693 
PhotoAccessHelperFavoriteExecute(napi_env env,void * data)3694 static void PhotoAccessHelperFavoriteExecute(napi_env env, void *data)
3695 {
3696     MediaLibraryTracer tracer;
3697     tracer.Start("PhotoAccessHelperFavoriteExecute");
3698 
3699     auto *context = static_cast<FileAssetAsyncContext *>(data);
3700     string uri;
3701     if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
3702         context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
3703         uri = PAH_UPDATE_PHOTO;
3704     } else {
3705         context->SaveError(-EINVAL);
3706         return;
3707     }
3708 
3709     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3710     Uri updateAssetUri(uri);
3711     DataSharePredicates predicates;
3712     DataShareValuesBucket valuesBucket;
3713     int32_t changedRows = 0;
3714     valuesBucket.Put(MediaColumn::MEDIA_IS_FAV, context->isFavorite ? IS_FAV : NOT_FAV);
3715     predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
3716     predicates.SetWhereArgs({ std::to_string(context->objectPtr->GetId()) });
3717 
3718     changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
3719     if (changedRows < 0) {
3720         context->SaveError(changedRows);
3721         NAPI_ERR_LOG("Failed to modify favorite state, err: %{public}d", changedRows);
3722     } else {
3723         context->objectPtr->SetFavorite(context->isFavorite);
3724         context->changedRows = changedRows;
3725     }
3726 }
3727 
PhotoAccessHelperFavorite(napi_env env,napi_callback_info info)3728 napi_value FileAssetNapi::PhotoAccessHelperFavorite(napi_env env, napi_callback_info info)
3729 {
3730     MediaLibraryTracer tracer;
3731     tracer.Start("PhotoAccessHelperFavorite");
3732 
3733     if (!MediaLibraryNapiUtils::IsSystemApp()) {
3734         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
3735         return nullptr;
3736     }
3737 
3738     napi_value ret = nullptr;
3739     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3740     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
3741     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
3742     NAPI_ASSERT(
3743         env, MediaLibraryNapiUtils::ParseArgsBoolCallBack(env, info, asyncContext, asyncContext->isFavorite) == napi_ok,
3744         "Failed to parse js args");
3745     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3746     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "FileAsset is nullptr");
3747 
3748     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperFavorite",
3749         PhotoAccessHelperFavoriteExecute, PhotoAccessHelperFavoriteComplete);
3750 }
3751 
PhotoAccessHelperGetThumbnail(napi_env env,napi_callback_info info)3752 napi_value FileAssetNapi::PhotoAccessHelperGetThumbnail(napi_env env, napi_callback_info info)
3753 {
3754     MediaLibraryTracer tracer;
3755     tracer.Start("PhotoAccessHelperGetThumbnail");
3756 
3757     napi_value result = nullptr;
3758     NAPI_CALL(env, napi_get_undefined(env, &result));
3759     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3760     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
3761 
3762     CHECK_COND_RET(MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_ZERO, ARGS_TWO) ==
3763         napi_ok, result, "Failed to get object info");
3764     result = GetJSArgsForGetThumbnail(env, asyncContext->argc, asyncContext->argv, asyncContext);
3765     ASSERT_NULLPTR_CHECK(env, result);
3766     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3767     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
3768     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
3769     result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperGetThumbnail",
3770         [](napi_env env, void *data) {
3771             auto context = static_cast<FileAssetAsyncContext*>(data);
3772             JSGetThumbnailExecute(context);
3773         },
3774         reinterpret_cast<CompleteCallback>(JSGetThumbnailCompleteCallback));
3775 
3776     return result;
3777 }
3778 
PhotoAccessHelperRequestPhoto(napi_env env,napi_callback_info info)3779 napi_value FileAssetNapi::PhotoAccessHelperRequestPhoto(napi_env env, napi_callback_info info)
3780 {
3781     MediaLibraryTracer tracer;
3782     tracer.Start("PhotoAccessHelperRequestPhoto");
3783 
3784     // request Photo function in API11 is system api, maybe public soon
3785     if (!MediaLibraryNapiUtils::IsSystemApp()) {
3786         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
3787         return nullptr;
3788     }
3789 
3790     napi_value result = nullptr;
3791     NAPI_CALL(env, napi_get_undefined(env, &result));
3792     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3793     CHECK_COND_WITH_MESSAGE(env, asyncContext != nullptr, "asyncContext context is null");
3794     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext,
3795         ARGS_ONE, ARGS_TWO) == napi_ok, "Failed to get object info");
3796     if (asyncContext->callbackRef == nullptr) {
3797         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Can not get callback function");
3798         return nullptr;
3799     }
3800     // use current parse args function temporary
3801     RequestPhotoType type = RequestPhotoType::REQUEST_ALL_THUMBNAILS;
3802     result = GetPhotoRequestArgs(env, asyncContext->argc, asyncContext->argv, asyncContext, type);
3803     ASSERT_NULLPTR_CHECK(env, result);
3804     auto obj = asyncContext->objectInfo;
3805     napi_value ret = nullptr;
3806     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectInfo, ret, "FileAsset is nullptr");
3807 
3808     RequestPhotoParams params = {
3809         .uri = obj->fileAssetPtr->GetUri(),
3810         .path = obj->fileAssetPtr->GetFilePath(),
3811         .size = asyncContext->size,
3812         .type = type
3813     };
3814     static std::once_flag onceFlag;
3815     std::call_once(onceFlag, []() mutable {
3816         thumbnailManager_ = ThumbnailManager::GetInstance();
3817         if (thumbnailManager_ != nullptr) {
3818             thumbnailManager_->Init();
3819         }
3820     });
3821     string requestId;
3822     if (thumbnailManager_ != nullptr) {
3823         requestId = thumbnailManager_->AddPhotoRequest(params, env, asyncContext->callbackRef);
3824     }
3825     napi_create_string_utf8(env, requestId.c_str(), NAPI_AUTO_LENGTH, &result);
3826     return result;
3827 }
3828 
PhotoAccessHelperCancelPhotoRequest(napi_env env,napi_callback_info info)3829 napi_value FileAssetNapi::PhotoAccessHelperCancelPhotoRequest(napi_env env, napi_callback_info info)
3830 {
3831     MediaLibraryTracer tracer;
3832     tracer.Start("PhotoAccessHelperCancelPhotoRequest");
3833 
3834     // request Photo function in API11 is system api, maybe public soon
3835     if (!MediaLibraryNapiUtils::IsSystemApp()) {
3836         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
3837         return nullptr;
3838     }
3839 
3840     napi_value ret = nullptr;
3841     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3842     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
3843 
3844     string requestKey;
3845     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_ONE,
3846         ARGS_ONE), OHOS_INVALID_PARAM_CODE);
3847     CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, asyncContext->argv[ARGS_ZERO], requestKey),
3848         OHOS_INVALID_PARAM_CODE);
3849     napi_value jsResult = nullptr;
3850     napi_get_undefined(env, &jsResult);
3851 
3852     if (thumbnailManager_ != nullptr) {
3853         thumbnailManager_->RemovePhotoRequest(requestKey);
3854     }
3855     return jsResult;
3856 }
3857 
PhotoAccessHelperSetHiddenExecute(napi_env env,void * data)3858 static void PhotoAccessHelperSetHiddenExecute(napi_env env, void *data)
3859 {
3860     MediaLibraryTracer tracer;
3861     tracer.Start("PhotoAccessHelperSetHiddenExecute");
3862 
3863     auto *context = static_cast<FileAssetAsyncContext *>(data);
3864     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3865     if (context->objectPtr->GetMediaType() != MEDIA_TYPE_IMAGE &&
3866         context->objectPtr->GetMediaType() != MEDIA_TYPE_VIDEO) {
3867         context->SaveError(-EINVAL);
3868         return;
3869     }
3870 
3871     string uri = PAH_HIDE_PHOTOS;
3872     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3873     Uri updateAssetUri(uri);
3874     DataSharePredicates predicates;
3875     predicates.In(MediaColumn::MEDIA_ID, vector<string>({ context->objectPtr->GetUri() }));
3876     DataShareValuesBucket valuesBucket;
3877     valuesBucket.Put(MediaColumn::MEDIA_HIDDEN, context->isHidden ? IS_HIDDEN : NOT_HIDDEN);
3878 
3879     int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
3880     if (changedRows < 0) {
3881         context->SaveError(changedRows);
3882         NAPI_ERR_LOG("Failed to modify hidden state, err: %{public}d", changedRows);
3883     } else {
3884         context->objectPtr->SetHidden(context->isHidden);
3885         context->changedRows = changedRows;
3886     }
3887 }
3888 
PhotoAccessHelperSetHiddenComplete(napi_env env,napi_status status,void * data)3889 static void PhotoAccessHelperSetHiddenComplete(napi_env env, napi_status status, void *data)
3890 {
3891     auto *context = static_cast<FileAssetAsyncContext*>(data);
3892     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3893     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3894     jsContext->status = false;
3895 
3896     if (context->error == ERR_DEFAULT) {
3897         napi_create_int32(env, context->changedRows, &jsContext->data);
3898         jsContext->status = true;
3899         napi_get_undefined(env, &jsContext->error);
3900     } else {
3901         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->changedRows,
3902             "Failed to modify hidden state");
3903         napi_get_undefined(env, &jsContext->data);
3904     }
3905 
3906     if (context->work != nullptr) {
3907         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3908             context->work, *jsContext);
3909     }
3910     delete context;
3911 }
3912 
PhotoAccessHelperSetHidden(napi_env env,napi_callback_info info)3913 napi_value FileAssetNapi::PhotoAccessHelperSetHidden(napi_env env, napi_callback_info info)
3914 {
3915     MediaLibraryTracer tracer;
3916     tracer.Start("PhotoAccessHelperSetHidden");
3917 
3918     if (!MediaLibraryNapiUtils::IsSystemApp()) {
3919         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
3920         return nullptr;
3921     }
3922 
3923     napi_value ret = nullptr;
3924     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3925     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
3926     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
3927     NAPI_ASSERT(
3928         env, MediaLibraryNapiUtils::ParseArgsBoolCallBack(env, info, asyncContext, asyncContext->isHidden) == napi_ok,
3929         "Failed to parse js args");
3930     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3931     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "FileAsset is nullptr");
3932 
3933     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperSetHidden",
3934         PhotoAccessHelperSetHiddenExecute, PhotoAccessHelperSetHiddenComplete);
3935 }
3936 
PhotoAccessHelperSetPendingExecute(napi_env env,void * data)3937 static void PhotoAccessHelperSetPendingExecute(napi_env env, void *data)
3938 {
3939     MediaLibraryTracer tracer;
3940     tracer.Start("PhotoAccessHelperSetPendingExecute");
3941 
3942     auto *context = static_cast<FileAssetAsyncContext *>(data);
3943     string uri = MEDIALIBRARY_DATA_URI + "/";
3944     if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
3945         context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
3946         uri += PAH_PHOTO + "/" + OPRN_PENDING;
3947     } else {
3948         context->SaveError(-EINVAL);
3949         return;
3950     }
3951 
3952     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3953     Uri updateAssetUri(uri);
3954     DataSharePredicates predicates;
3955     DataShareValuesBucket valuesBucket;
3956     int32_t changedRows = 0;
3957     valuesBucket.Put(MediaColumn::MEDIA_TIME_PENDING, context->isPending ? 1 : 0);
3958     predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
3959     predicates.SetWhereArgs({ std::to_string(context->objectPtr->GetId()) });
3960 
3961     changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
3962     if (changedRows < 0) {
3963         if (changedRows == E_PERMISSION_DENIED) {
3964             context->error = OHOS_PERMISSION_DENIED_CODE;
3965         } else {
3966             context->SaveError(changedRows);
3967         }
3968 
3969         NAPI_ERR_LOG("Failed to modify pending state, err: %{public}d", changedRows);
3970     } else {
3971         context->changedRows = changedRows;
3972         context->objectPtr->SetTimePending((context->isPending) ? 1 : 0);
3973     }
3974 }
3975 
PhotoAccessHelperSetPendingComplete(napi_env env,napi_status status,void * data)3976 static void PhotoAccessHelperSetPendingComplete(napi_env env, napi_status status, void *data)
3977 {
3978     auto *context = static_cast<FileAssetAsyncContext*>(data);
3979     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3980     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3981     jsContext->status = false;
3982 
3983     if (context->error == ERR_DEFAULT) {
3984         napi_create_int32(env, context->changedRows, &jsContext->data);
3985         jsContext->status = true;
3986         napi_get_undefined(env, &jsContext->error);
3987     } else {
3988         context->HandleError(env, jsContext->error);
3989         napi_get_undefined(env, &jsContext->data);
3990     }
3991 
3992     if (context->work != nullptr) {
3993         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3994             context->work, *jsContext);
3995     }
3996     delete context;
3997 }
3998 
PhotoAccessHelperSetPending(napi_env env,napi_callback_info info)3999 napi_value FileAssetNapi::PhotoAccessHelperSetPending(napi_env env, napi_callback_info info)
4000 {
4001     MediaLibraryTracer tracer;
4002     tracer.Start("PhotoAccessHelperSetPending");
4003 
4004     if (!MediaLibraryNapiUtils::IsSystemApp()) {
4005         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4006         return nullptr;
4007     }
4008 
4009     napi_value ret = nullptr;
4010     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
4011     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
4012     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4013     CHECK_COND_WITH_MESSAGE(env,
4014         MediaLibraryNapiUtils::ParseArgsBoolCallBack(env, info, asyncContext, asyncContext->isPending) == napi_ok,
4015         "Failed to parse js args");
4016     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4017     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "FileAsset is nullptr");
4018 
4019     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperSetPending",
4020         PhotoAccessHelperSetPendingExecute, PhotoAccessHelperSetPendingComplete);
4021 }
4022 
PhotoAccessHelperSetUserCommentComplete(napi_env env,napi_status status,void * data)4023 static void PhotoAccessHelperSetUserCommentComplete(napi_env env, napi_status status, void *data)
4024 {
4025     auto *context = static_cast<FileAssetAsyncContext*>(data);
4026     auto jsContext = make_unique<JSAsyncContextOutput>();
4027     jsContext->status = false;
4028 
4029     if (context->error == ERR_DEFAULT) {
4030         napi_create_int32(env, context->changedRows, &jsContext->data);
4031         jsContext->status = true;
4032         napi_get_undefined(env, &jsContext->error);
4033     } else {
4034         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
4035             "Failed to edit user comment");
4036         napi_get_undefined(env, &jsContext->data);
4037     }
4038 
4039     if (context->work != nullptr) {
4040         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4041             context->work, *jsContext);
4042     }
4043     delete context;
4044 }
4045 
UserFileMgrGetJsonComplete(napi_env env,napi_status status,void * data)4046 static void UserFileMgrGetJsonComplete(napi_env env, napi_status status, void *data)
4047 {
4048     MediaLibraryTracer tracer;
4049     tracer.Start("UserFileMgrGetJsonComplete");
4050     auto *context = static_cast<FileAssetAsyncContext *>(data);
4051     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4052     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4053     jsContext->status = false;
4054     if (context->error == ERR_DEFAULT) {
4055         napi_create_string_utf8(env, context->jsonStr.c_str(), NAPI_AUTO_LENGTH, &jsContext->data);
4056         napi_get_undefined(env, &jsContext->error);
4057         jsContext->status = true;
4058     } else {
4059         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
4060             "UserFileClient is invalid");
4061         napi_get_undefined(env, &jsContext->data);
4062     }
4063 
4064     tracer.Finish();
4065     if (context->work != nullptr) {
4066         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4067                                                    context->work, *jsContext);
4068     }
4069     delete context;
4070 }
4071 
PhotoAccessHelperSetUserCommentExecute(napi_env env,void * data)4072 static void PhotoAccessHelperSetUserCommentExecute(napi_env env, void *data)
4073 {
4074     MediaLibraryTracer tracer;
4075     tracer.Start("PhotoAccessHelperSetUserCommentExecute");
4076 
4077     auto *context = static_cast<FileAssetAsyncContext *>(data);
4078     if (context->objectPtr->GetMediaType() != MEDIA_TYPE_IMAGE) {
4079         context->error = -EINVAL;
4080         return;
4081     }
4082 
4083     string uri = PAH_EDIT_USER_COMMENT_PHOTO;
4084     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4085     Uri editUserCommentUri(uri);
4086     DataSharePredicates predicates;
4087     DataShareValuesBucket valuesBucket;
4088     valuesBucket.Put(PhotoColumn::PHOTO_USER_COMMENT, context->userComment);
4089     predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
4090     predicates.SetWhereArgs({std::to_string(context->objectPtr->GetId())});
4091     int32_t changedRows = UserFileClient::Update(editUserCommentUri, predicates, valuesBucket);
4092     if (changedRows < 0) {
4093         context->SaveError(changedRows);
4094         NAPI_ERR_LOG("Failed to modify user comment, err: %{public}d", changedRows);
4095     } else {
4096         context->objectPtr->SetUserComment(context->userComment);
4097         context->changedRows = changedRows;
4098     }
4099 }
4100 
PhotoAccessHelperSetUserComment(napi_env env,napi_callback_info info)4101 napi_value FileAssetNapi::PhotoAccessHelperSetUserComment(napi_env env, napi_callback_info info)
4102 {
4103     MediaLibraryTracer tracer;
4104     tracer.Start("PhotoAccessHelperSetUserComment");
4105 
4106     if (!MediaLibraryNapiUtils::IsSystemApp()) {
4107         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4108         return nullptr;
4109     }
4110 
4111     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
4112     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4113     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, asyncContext, asyncContext->userComment),
4114         JS_ERR_PARAMETER_INVALID);
4115     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4116     if (asyncContext->objectPtr == nullptr) {
4117         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
4118         return nullptr;
4119     }
4120 
4121     if (asyncContext->userComment.length() > USER_COMMENT_MAX_LEN) {
4122         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "user comment too long");
4123         return nullptr;
4124     }
4125 
4126     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperSetUserComment",
4127         PhotoAccessHelperSetUserCommentExecute, PhotoAccessHelperSetUserCommentComplete);
4128 }
4129 
PhotoAccessHelperGetAnalysisData(napi_env env,napi_callback_info info)4130 napi_value FileAssetNapi::PhotoAccessHelperGetAnalysisData(napi_env env, napi_callback_info info)
4131 {
4132     MediaLibraryTracer tracer;
4133     tracer.Start("PhotoAccessHelperGetAnalysisData");
4134 
4135     napi_value result = nullptr;
4136     NAPI_CALL(env, napi_get_undefined(env, &result));
4137     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
4138     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
4139     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsNumberCallback(env, info, asyncContext, asyncContext->analysisType),
4140         JS_ERR_PARAMETER_INVALID);
4141     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4142     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
4143     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4144     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperGetAnalysisData",
4145         [](napi_env env, void *data) {
4146             auto context = static_cast<FileAssetAsyncContext*>(data);
4147             JSGetAnalysisDataExecute(context);
4148         },
4149         reinterpret_cast<CompleteCallback>(JSGetAnalysisDataCompleteCallback));
4150 }
4151 
UserFileMgrGetJsonExecute(napi_env env,void * data)4152 static void UserFileMgrGetJsonExecute(napi_env env, void *data)
4153 {
4154     MediaLibraryTracer tracer;
4155     tracer.Start("UserFileMgrGetJsonExecute");
4156     auto *context = static_cast<FileAssetAsyncContext *>(data);
4157     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4158     context->jsonStr = context->objectPtr->GetAssetJson();
4159     return;
4160 }
4161 
UserFileMgrGetJson(napi_env env,napi_callback_info info)4162 napi_value FileAssetNapi::UserFileMgrGetJson(napi_env env, napi_callback_info info)
4163 {
4164     MediaLibraryTracer tracer;
4165     tracer.Start("UserFileMgrGetJson");
4166     auto asyncContext = make_unique<FileAssetAsyncContext>();
4167     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
4168     NAPI_ASSERT(env, MediaLibraryNapiUtils::ParseArgsOnlyCallBack(env, info, asyncContext) == napi_ok,
4169         "Failed to parse js args");
4170     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4171     napi_value ret = nullptr;
4172     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "FileAsset is nullptr");
4173     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrGetJson",
4174         UserFileMgrGetJsonExecute, UserFileMgrGetJsonComplete);
4175 }
4176 
GetEditTimeFromResultSet(const shared_ptr<DataShare::DataShareResultSet> & resultSet,int64_t & editTime)4177 static bool GetEditTimeFromResultSet(const shared_ptr<DataShare::DataShareResultSet> &resultSet,
4178     int64_t &editTime)
4179 {
4180     if (resultSet == nullptr) {
4181         NAPI_ERR_LOG("ResultSet is null");
4182         return false;
4183     }
4184     int32_t count = 0;
4185     int32_t errCode = resultSet->GetRowCount(count);
4186     if (errCode != DataShare::E_OK) {
4187         NAPI_ERR_LOG("Can not get row count from resultSet, errCode=%{public}d", errCode);
4188         return false;
4189     }
4190     if (count == 0) {
4191         NAPI_ERR_LOG("Can not find photo edit time from database");
4192         return false;
4193     }
4194     errCode = resultSet->GoToFirstRow();
4195     if (errCode != DataShare::E_OK) {
4196         NAPI_ERR_LOG("ResultSet GotoFirstRow failed, errCode=%{public}d", errCode);
4197         return false;
4198     }
4199     int32_t index = 0;
4200     errCode = resultSet->GetColumnIndex(PhotoColumn::PHOTO_EDIT_TIME, index);
4201     if (errCode != DataShare::E_OK) {
4202         NAPI_ERR_LOG("ResultSet GetColumnIndex failed, errCode=%{public}d", errCode);
4203         return false;
4204     }
4205     errCode = resultSet->GetLong(index, editTime);
4206     if (errCode != DataShare::E_OK) {
4207         NAPI_ERR_LOG("ResultSet GetLong failed, errCode=%{public}d", errCode);
4208         return false;
4209     }
4210     return true;
4211 }
4212 
PhotoAccessHelperIsEditedExecute(napi_env env,void * data)4213 static void PhotoAccessHelperIsEditedExecute(napi_env env, void *data)
4214 {
4215     MediaLibraryTracer tracer;
4216     tracer.Start("PhotoAccessHelperIsEditedExecute");
4217     auto *context = static_cast<FileAssetAsyncContext *>(data);
4218     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4219     int32_t fileId = context->objectPtr->GetId();
4220     string queryUriStr = PAH_QUERY_PHOTO;
4221     MediaLibraryNapiUtils::UriAppendKeyValue(queryUriStr, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4222     Uri uri(queryUriStr);
4223     DataShare::DataSharePredicates predicates;
4224     predicates.EqualTo(MediaColumn::MEDIA_ID, to_string(fileId));
4225     DataShare::DataShareValuesBucket values;
4226     vector<string> columns = { PhotoColumn::PHOTO_EDIT_TIME };
4227     int32_t errCode = 0;
4228     int64_t editTime = 0;
4229     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
4230     if (!GetEditTimeFromResultSet(resultSet, editTime)) {
4231         if (errCode == E_PERMISSION_DENIED) {
4232             context->error = OHOS_PERMISSION_DENIED_CODE;
4233         } else {
4234             context->SaveError(E_FAIL);
4235         }
4236     } else {
4237         if (editTime == 0) {
4238             context->hasEdit = false;
4239         } else {
4240             context->hasEdit = true;
4241         }
4242     }
4243 }
4244 
PhotoAccessHelperIsEditedComplete(napi_env env,napi_status status,void * data)4245 static void PhotoAccessHelperIsEditedComplete(napi_env env, napi_status status, void *data)
4246 {
4247     auto *context = static_cast<FileAssetAsyncContext *>(data);
4248     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4249 
4250     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4251     jsContext->status = false;
4252     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
4253     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
4254 
4255     if (context->error == ERR_DEFAULT) {
4256         CHECK_ARGS_RET_VOID(env, napi_get_boolean(env, context->hasEdit, &jsContext->data), JS_INNER_FAIL);
4257         jsContext->status = true;
4258     } else {
4259         context->HandleError(env, jsContext->error);
4260     }
4261 
4262     if (context->work != nullptr) {
4263         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4264                                                    context->work, *jsContext);
4265     }
4266     delete context;
4267 }
4268 
PhotoAccessHelperIsEdited(napi_env env,napi_callback_info info)4269 napi_value FileAssetNapi::PhotoAccessHelperIsEdited(napi_env env, napi_callback_info info)
4270 {
4271     MediaLibraryTracer tracer;
4272     tracer.Start("PhotoAccessHelperIsEdited");
4273 
4274     // edit function in API11 is system api, maybe public soon
4275     if (!MediaLibraryNapiUtils::IsSystemApp()) {
4276         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4277         return nullptr;
4278     }
4279 
4280     auto asyncContext = make_unique<FileAssetAsyncContext>();
4281     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4282     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::ParseArgsOnlyCallBack(env, info, asyncContext) == napi_ok,
4283         "Failed to parse js args");
4284     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4285     napi_value ret = nullptr;
4286     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "PhotoAsset is nullptr");
4287     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperIsEdited",
4288         PhotoAccessHelperIsEditedExecute, PhotoAccessHelperIsEditedComplete);
4289 }
4290 
PhotoAccessHelperRequestEditDataExecute(napi_env env,void * data)4291 static void PhotoAccessHelperRequestEditDataExecute(napi_env env, void *data)
4292 {
4293     MediaLibraryTracer tracer;
4294     tracer.Start("PhotoAccessHelperRequestEditDataExecute");
4295     auto *context = static_cast<FileAssetAsyncContext *>(data);
4296     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4297     bool isValid = false;
4298     string fileUri = context->valuesBucket.Get(MEDIA_DATA_DB_URI, isValid);
4299     if (!isValid) {
4300         context->error = OHOS_INVALID_PARAM_CODE;
4301         return;
4302     }
4303     MediaFileUtils::UriAppendKeyValue(fileUri, MEDIA_OPERN_KEYWORD, EDIT_DATA_REQUEST);
4304     Uri uri(fileUri);
4305     UniqueFd uniqueFd(UserFileClient::OpenFile(uri, "r"));
4306     if (uniqueFd.Get() <= 0) {
4307         if (uniqueFd.Get() == E_PERMISSION_DENIED) {
4308             context->error = OHOS_PERMISSION_DENIED_CODE;
4309         } else {
4310             context->SaveError(uniqueFd.Get());
4311         }
4312         NAPI_ERR_LOG("Photo request edit data failed, ret: %{public}d", uniqueFd.Get());
4313     } else {
4314         struct stat fileInfo;
4315         if (fstat(uniqueFd.Get(), &fileInfo) == 0) {
4316             off_t fileSize = fileInfo.st_size;
4317             if (fileSize < 0) {
4318                 NAPI_ERR_LOG("fileBuffer error : %{public}ld", static_cast<long>(fileSize));
4319                 context->SaveError(E_FAIL);
4320                 return;
4321             }
4322             context->editDataBuffer = static_cast<char*>(malloc(fileSize + 1));
4323             if (!context->editDataBuffer) {
4324                 NAPI_ERR_LOG("Photo request edit data failed, fd: %{public}d", uniqueFd.Get());
4325                 context->SaveError(E_FAIL);
4326                 return;
4327             }
4328             ssize_t bytes = read(uniqueFd.Get(), context->editDataBuffer, fileSize);
4329             if (bytes < 0) {
4330                 NAPI_ERR_LOG("Read edit data failed, errno: %{public}d", errno);
4331                 context->SaveError(E_FAIL);
4332                 return;
4333             }
4334             context->editDataBuffer[bytes] = '\0';
4335         } else {
4336             NAPI_ERR_LOG("can not get stat errno:%{public}d", errno);
4337             context->SaveError(E_FAIL);
4338         }
4339     }
4340 }
4341 
GetEditDataString(char * editDataBuffer,string & result)4342 static void GetEditDataString(char* editDataBuffer, string& result)
4343 {
4344     if (editDataBuffer == nullptr) {
4345         result = "";
4346         NAPI_WARN_LOG("editDataBuffer is nullptr");
4347         return;
4348     }
4349 
4350     string editDataStr(editDataBuffer);
4351     if (!nlohmann::json::accept(editDataStr)) {
4352         result = editDataStr;
4353         return;
4354     }
4355 
4356     nlohmann::json editDataJson = nlohmann::json::parse(editDataStr);
4357     if (editDataJson.contains(COMPATIBLE_FORMAT) && editDataJson.contains(FORMAT_VERSION) &&
4358         editDataJson.contains(EDIT_DATA) && editDataJson.contains(APP_ID)) {
4359         // edit data saved by media change request
4360         result = editDataJson.at(EDIT_DATA);
4361     } else {
4362         // edit data saved by commitEditedAsset
4363         result = editDataStr;
4364     }
4365 }
4366 
GetEditDataObject(napi_env env,char * editDataBuffer)4367 static napi_value GetEditDataObject(napi_env env, char* editDataBuffer)
4368 {
4369     if (editDataBuffer == nullptr) {
4370         NAPI_WARN_LOG("editDataBuffer is nullptr");
4371         return MediaAssetEditDataNapi::CreateMediaAssetEditData(env, "", "", "");
4372     }
4373 
4374     string editDataStr(editDataBuffer);
4375     if (!nlohmann::json::accept(editDataStr)) {
4376         return MediaAssetEditDataNapi::CreateMediaAssetEditData(env, "", "", editDataStr);
4377     }
4378 
4379     nlohmann::json editDataJson = nlohmann::json::parse(editDataStr);
4380     if (editDataJson.contains(COMPATIBLE_FORMAT) && editDataJson.contains(FORMAT_VERSION) &&
4381         editDataJson.contains(EDIT_DATA) && editDataJson.contains(APP_ID)) {
4382         // edit data saved by media change request
4383         return MediaAssetEditDataNapi::CreateMediaAssetEditData(env,
4384             editDataJson.at(COMPATIBLE_FORMAT), editDataJson.at(FORMAT_VERSION), editDataJson.at(EDIT_DATA));
4385     }
4386 
4387     // edit data saved by commitEditedAsset
4388     return MediaAssetEditDataNapi::CreateMediaAssetEditData(env, "", "", editDataStr);
4389 }
4390 
PhotoAccessHelperRequestEditDataComplete(napi_env env,napi_status status,void * data)4391 static void PhotoAccessHelperRequestEditDataComplete(napi_env env, napi_status status, void *data)
4392 {
4393     auto *context = static_cast<FileAssetAsyncContext *>(data);
4394     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4395 
4396     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4397     jsContext->status = false;
4398     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
4399     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
4400 
4401     if (context->error == ERR_DEFAULT) {
4402         string editDataStr;
4403         GetEditDataString(context->editDataBuffer, editDataStr);
4404         CHECK_ARGS_RET_VOID(env, napi_create_string_utf8(env, editDataStr.c_str(),
4405             NAPI_AUTO_LENGTH, &jsContext->data), JS_INNER_FAIL);
4406         jsContext->status = true;
4407     } else {
4408         context->HandleError(env, jsContext->error);
4409     }
4410 
4411     if (context->work != nullptr) {
4412         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4413                                                    context->work, *jsContext);
4414     }
4415     if (context->editDataBuffer != nullptr) {
4416         free(context->editDataBuffer);
4417     }
4418     delete context;
4419 }
4420 
PhotoAccessHelperGetEditDataComplete(napi_env env,napi_status status,void * data)4421 static void PhotoAccessHelperGetEditDataComplete(napi_env env, napi_status status, void* data)
4422 {
4423     auto* context = static_cast<FileAssetAsyncContext*>(data);
4424     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4425 
4426     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4427     jsContext->status = false;
4428     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
4429     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
4430     if (context->error == ERR_DEFAULT) {
4431         jsContext->data = GetEditDataObject(env, context->editDataBuffer);
4432         jsContext->status = true;
4433     } else {
4434         context->HandleError(env, jsContext->error);
4435     }
4436 
4437     if (context->work != nullptr) {
4438         MediaLibraryNapiUtils::InvokeJSAsyncMethod(
4439             env, context->deferred, context->callbackRef, context->work, *jsContext);
4440     }
4441     if (context->editDataBuffer != nullptr) {
4442         free(context->editDataBuffer);
4443     }
4444     delete context;
4445 }
4446 
PhotoAccessHelperRequestEditData(napi_env env,napi_callback_info info)4447 napi_value FileAssetNapi::PhotoAccessHelperRequestEditData(napi_env env, napi_callback_info info)
4448 {
4449     MediaLibraryTracer tracer;
4450     tracer.Start("PhotoAccessHelperRequestEditData");
4451 
4452     // edit function in API11 is system api, maybe public soon
4453     if (!MediaLibraryNapiUtils::IsSystemApp()) {
4454         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4455         return nullptr;
4456     }
4457 
4458     auto asyncContext = make_unique<FileAssetAsyncContext>();
4459     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4460     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::ParseArgsOnlyCallBack(env, info, asyncContext) == napi_ok,
4461         "Failed to parse js args");
4462     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4463     napi_value ret = nullptr;
4464     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "PhotoAsset is nullptr");
4465     auto fileUri = asyncContext->objectInfo->GetFileUri();
4466     MediaLibraryNapiUtils::UriAppendKeyValue(fileUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4467     asyncContext->valuesBucket.Put(MEDIA_DATA_DB_URI, fileUri);
4468     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperRequestEditData",
4469         PhotoAccessHelperRequestEditDataExecute, PhotoAccessHelperRequestEditDataComplete);
4470 }
4471 
PhotoAccessHelperGetEditData(napi_env env,napi_callback_info info)4472 napi_value FileAssetNapi::PhotoAccessHelperGetEditData(napi_env env, napi_callback_info info)
4473 {
4474     MediaLibraryTracer tracer;
4475     tracer.Start("PhotoAccessHelperGetEditData");
4476 
4477     if (!MediaLibraryNapiUtils::IsSystemApp()) {
4478         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4479         return nullptr;
4480     }
4481 
4482     auto asyncContext = make_unique<FileAssetAsyncContext>();
4483     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4484     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::ParseArgsOnlyCallBack(env, info, asyncContext) == napi_ok,
4485         "Failed to parse js args");
4486     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4487     napi_value ret = nullptr;
4488     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "PhotoAsset is null");
4489     auto fileUri = asyncContext->objectInfo->GetFileUri();
4490     MediaLibraryNapiUtils::UriAppendKeyValue(fileUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4491     asyncContext->valuesBucket.Put(MEDIA_DATA_DB_URI, fileUri);
4492     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperGetEditData",
4493         PhotoAccessHelperRequestEditDataExecute, PhotoAccessHelperGetEditDataComplete);
4494 }
4495 
PhotoAccessHelperRequestSourceExecute(napi_env env,void * data)4496 static void PhotoAccessHelperRequestSourceExecute(napi_env env, void *data)
4497 {
4498     MediaLibraryTracer tracer;
4499     tracer.Start("PhotoAccessHelperRequestSourceExecute");
4500     auto *context = static_cast<FileAssetAsyncContext *>(data);
4501     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4502     bool isValid = false;
4503     string fileUri = context->valuesBucket.Get(MEDIA_DATA_DB_URI, isValid);
4504     if (!isValid) {
4505         context->error = OHOS_INVALID_PARAM_CODE;
4506         return;
4507     }
4508     MediaFileUtils::UriAppendKeyValue(fileUri, MEDIA_OPERN_KEYWORD, SOURCE_REQUEST);
4509     Uri uri(fileUri);
4510     int32_t retVal = UserFileClient::OpenFile(uri, "r");
4511     if (retVal <= 0) {
4512         if (retVal == E_PERMISSION_DENIED) {
4513             context->error = OHOS_PERMISSION_DENIED_CODE;
4514         } else {
4515             context->SaveError(retVal);
4516         }
4517         NAPI_ERR_LOG("Photo request edit data failed, ret: %{public}d", retVal);
4518     } else {
4519         context->fd = retVal;
4520         context->objectPtr->SetOpenStatus(retVal, OPEN_TYPE_READONLY);
4521     }
4522 }
4523 
PhotoAccessHelperRequestSourceComplete(napi_env env,napi_status status,void * data)4524 static void PhotoAccessHelperRequestSourceComplete(napi_env env, napi_status status, void *data)
4525 {
4526     auto *context = static_cast<FileAssetAsyncContext *>(data);
4527     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4528 
4529     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4530     jsContext->status = false;
4531 
4532     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
4533     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
4534     if (context->error == ERR_DEFAULT) {
4535         CHECK_ARGS_RET_VOID(env, napi_create_int32(env, context->fd, &jsContext->data), JS_INNER_FAIL);
4536         jsContext->status = true;
4537     } else {
4538         context->HandleError(env, jsContext->error);
4539     }
4540 
4541     if (context->work != nullptr) {
4542         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4543                                                    context->work, *jsContext);
4544     }
4545     delete context;
4546 }
4547 
PhotoAccessHelperRequestSource(napi_env env,napi_callback_info info)4548 napi_value FileAssetNapi::PhotoAccessHelperRequestSource(napi_env env, napi_callback_info info)
4549 {
4550     MediaLibraryTracer tracer;
4551     tracer.Start("PhotoAccessHelperRequestSource");
4552 
4553     // edit function in API11 is system api, maybe public soon
4554     if (!MediaLibraryNapiUtils::IsSystemApp()) {
4555         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4556         return nullptr;
4557     }
4558 
4559     auto asyncContext = make_unique<FileAssetAsyncContext>();
4560     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4561     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::ParseArgsOnlyCallBack(env, info, asyncContext) == napi_ok,
4562         "Failed to parse js args");
4563     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4564     napi_value ret = nullptr;
4565     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "PhotoAsset is nullptr");
4566     auto fileUri = asyncContext->objectInfo->GetFileUri();
4567     MediaLibraryNapiUtils::UriAppendKeyValue(fileUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4568     asyncContext->valuesBucket.Put(MEDIA_DATA_DB_URI, fileUri);
4569     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperRequestSource",
4570         PhotoAccessHelperRequestSourceExecute, PhotoAccessHelperRequestSourceComplete);
4571 }
4572 
GetFileUriFd(FileAssetAsyncContext * context)4573 static int32_t GetFileUriFd(FileAssetAsyncContext *context)
4574 {
4575     string uriRealPath = AppFileService::ModuleFileUri::FileUri(context->uri).GetRealPath();
4576     if (uriRealPath.empty()) {
4577         NAPI_ERR_LOG("Can not get file in path by uri %{private}s", context->uri.c_str());
4578         context->SaveError(E_FAIL);
4579         return E_FAIL;
4580     }
4581     int32_t fd = open(uriRealPath.c_str(), O_RDONLY);
4582     if (fd < 0) {
4583         NAPI_ERR_LOG("Can not open fileUri, ret: %{public}d", fd);
4584         context->SaveError(E_FAIL);
4585         return E_FAIL;
4586     }
4587     return fd;
4588 }
4589 
PhotoAccessHelperCommitEditExecute(napi_env env,void * data)4590 static void PhotoAccessHelperCommitEditExecute(napi_env env, void *data)
4591 {
4592     MediaLibraryTracer tracer;
4593     tracer.Start("PhotoAccessHelperCommitEditExecute");
4594     auto *context = static_cast<FileAssetAsyncContext *>(data);
4595     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4596     UniqueFd uriFd(GetFileUriFd(context));
4597     CHECK_IF_EQUAL(uriFd.Get() > 0, "Can not open fileUri");
4598 
4599     bool isValid = false;
4600     string fileUri = context->valuesBucket.Get(MEDIA_DATA_DB_URI, isValid);
4601     if (!isValid) {
4602         context->error = OHOS_INVALID_PARAM_CODE;
4603         return;
4604     }
4605     MediaFileUtils::UriAppendKeyValue(fileUri, MEDIA_OPERN_KEYWORD, COMMIT_REQUEST);
4606     Uri uri(fileUri);
4607     UniqueFd fd(UserFileClient::OpenFile(uri, "rw"));
4608     if (fd.Get() <= 0) {
4609         if (fd.Get() == E_PERMISSION_DENIED) {
4610             context->error = OHOS_PERMISSION_DENIED_CODE;
4611         } else {
4612             context->SaveError(fd.Get());
4613         }
4614         NAPI_ERR_LOG("File request edit data failed, ret: %{public}d", fd.Get());
4615     } else {
4616         if (ftruncate(fd.Get(), 0) == -1) {
4617             NAPI_ERR_LOG("Can not erase content from old file, errno:%{public}d", errno);
4618             context->SaveError(E_FAIL);
4619             return;
4620         }
4621         if (!MediaFileUtils::CopyFile(uriFd.Get(), fd.Get())) {
4622             NAPI_ERR_LOG("Failed to copy file: rfd:%{public}d, wfd:%{public}d, errno:%{public}d",
4623                 uriFd.Get(), fd.Get(), errno);
4624             context->SaveError(E_FAIL);
4625             return;
4626         }
4627         NAPI_INFO_LOG("commit edit asset copy file finished, fileUri:%{public}s", fileUri.c_str());
4628         string insertUriStr = PAH_COMMIT_EDIT_PHOTOS;
4629         MediaLibraryNapiUtils::UriAppendKeyValue(insertUriStr, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4630         Uri insertUri(insertUriStr);
4631         int32_t ret = UserFileClient::Insert(insertUri, context->valuesBucket);
4632         if (ret != E_SUCCESS) {
4633             if (ret == E_PERMISSION_DENIED) {
4634                 context->error = OHOS_PERMISSION_DENIED_CODE;
4635             } else {
4636                 context->SaveError(ret);
4637             }
4638             NAPI_ERR_LOG("File commit edit execute failed");
4639         }
4640     }
4641 }
4642 
PhotoAccessHelperCommitEditComplete(napi_env env,napi_status status,void * data)4643 static void PhotoAccessHelperCommitEditComplete(napi_env env, napi_status status, void *data)
4644 {
4645     auto *context = static_cast<FileAssetAsyncContext *>(data);
4646     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4647 
4648     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4649     jsContext->status = false;
4650 
4651     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
4652     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
4653     if (context->error == ERR_DEFAULT) {
4654         jsContext->status = true;
4655     } else {
4656         context->HandleError(env, jsContext->error);
4657     }
4658 
4659     if (context->work != nullptr) {
4660         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4661                                                    context->work, *jsContext);
4662     }
4663     delete context;
4664 }
4665 
PhotoAccessHelperCommitEditedAsset(napi_env env,napi_callback_info info)4666 napi_value FileAssetNapi::PhotoAccessHelperCommitEditedAsset(napi_env env, napi_callback_info info)
4667 {
4668     MediaLibraryTracer tracer;
4669     tracer.Start("PhotoAccessHelperCommitEditedAsset");
4670 
4671     // edit function in API11 is system api, maybe public soon
4672     if (!MediaLibraryNapiUtils::IsSystemApp()) {
4673         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4674         return nullptr;
4675     }
4676 
4677     auto asyncContext = make_unique<FileAssetAsyncContext>();
4678     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4679     CHECK_ARGS_THROW_INVALID_PARAM(env,
4680         MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_TWO, ARGS_THREE));
4681     string editData;
4682     const static int32_t EDIT_DATA_MAX_LENGTH = 65536;
4683     CHECK_ARGS_THROW_INVALID_PARAM(env,
4684         MediaLibraryNapiUtils::GetParamStringWithLength(env, asyncContext->argv[0], EDIT_DATA_MAX_LENGTH, editData));
4685     CHECK_ARGS_THROW_INVALID_PARAM(env,
4686         MediaLibraryNapiUtils::GetParamStringPathMax(env, asyncContext->argv[1], asyncContext->uri));
4687     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4688     napi_value ret = nullptr;
4689     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "PhotoAsset is nullptr");
4690     auto fileUri = asyncContext->objectInfo->GetFileUri();
4691     MediaLibraryNapiUtils::UriAppendKeyValue(fileUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4692     asyncContext->valuesBucket.Put(MEDIA_DATA_DB_URI, fileUri);
4693     asyncContext->valuesBucket.Put(EDIT_DATA, editData);
4694     asyncContext->valuesBucket.Put(MediaColumn::MEDIA_ID, asyncContext->objectPtr->GetId());
4695     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperCommitEditedAsset",
4696         PhotoAccessHelperCommitEditExecute, PhotoAccessHelperCommitEditComplete);
4697 }
4698 
PhotoAccessHelperRevertToOriginalExecute(napi_env env,void * data)4699 static void PhotoAccessHelperRevertToOriginalExecute(napi_env env, void *data)
4700 {
4701     MediaLibraryTracer tracer;
4702     tracer.Start("PhotoAccessHelperRevertToOriginalExecute");
4703     auto *context = static_cast<FileAssetAsyncContext *>(data);
4704     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4705     string uriString = PAH_REVERT_EDIT_PHOTOS;
4706     MediaFileUtils::UriAppendKeyValue(uriString, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4707     Uri uri(uriString);
4708     int32_t ret = UserFileClient::Insert(uri, context->valuesBucket);
4709     if (ret < 0) {
4710         if (ret == E_PERMISSION_DENIED) {
4711             context->error = OHOS_PERMISSION_DENIED_CODE;
4712         } else {
4713             context->SaveError(ret);
4714         }
4715         NAPI_ERR_LOG("Photo revert edit data failed, ret: %{public}d", ret);
4716     }
4717 }
4718 
PhotoAccessHelperRevertToOriginalComplete(napi_env env,napi_status status,void * data)4719 static void PhotoAccessHelperRevertToOriginalComplete(napi_env env, napi_status status, void *data)
4720 {
4721     auto *context = static_cast<FileAssetAsyncContext *>(data);
4722     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4723 
4724     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4725     jsContext->status = false;
4726     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
4727     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
4728 
4729     if (context->error == ERR_DEFAULT) {
4730         jsContext->status = true;
4731     } else {
4732         context->HandleError(env, jsContext->error);
4733     }
4734 
4735     if (context->work != nullptr) {
4736         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4737                                                    context->work, *jsContext);
4738     }
4739     delete context;
4740 }
4741 
PhotoAccessHelperRevertToOriginal(napi_env env,napi_callback_info info)4742 napi_value FileAssetNapi::PhotoAccessHelperRevertToOriginal(napi_env env, napi_callback_info info)
4743 {
4744     MediaLibraryTracer tracer;
4745     tracer.Start("PhotoAccessHelperRevertToOriginal");
4746 
4747     // edit function in API11 is system api, maybe public soon
4748     if (!MediaLibraryNapiUtils::IsSystemApp()) {
4749         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4750         return nullptr;
4751     }
4752 
4753     auto asyncContext = make_unique<FileAssetAsyncContext>();
4754     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4755     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::ParseArgsOnlyCallBack(env, info, asyncContext) == napi_ok,
4756         "Failed to parse js args");
4757     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4758     napi_value ret = nullptr;
4759     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "PhotoAsset is nullptr");
4760     asyncContext->valuesBucket.Put(MediaColumn::MEDIA_ID, asyncContext->objectPtr->GetId());
4761     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperRevertToOriginal",
4762         PhotoAccessHelperRevertToOriginalExecute, PhotoAccessHelperRevertToOriginalComplete);
4763 }
4764 } // namespace Media
4765 } // namespace OHOS
4766