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