• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "media_asset_change_request_impl.h"
17 
18 #include <sys/sendfile.h>
19 
20 #include "ability_runtime/cj_ability_context.h"
21 #include "access_token.h"
22 #include "accesstoken_kit.h"
23 #include "datashare_helper.h"
24 #include "datashare_predicates.h"
25 #include "delete_callback.h"
26 #include "directory_ex.h"
27 #include "file_uri.h"
28 #include "image_packer.h"
29 #include "media_file_utils.h"
30 #include "permission_utils.h"
31 #include "userfile_manager_types.h"
32 
33 using namespace OHOS::Security::AccessToken;
34 
35 namespace OHOS {
36 namespace Media {
37 constexpr int64_t CREATE_ASSET_REQUEST_PENDING = -4;
38 constexpr int32_t MAX_DELETE_NUMBER = 300;
39 const std::string DEFAULT_TITLE_TIME_FORMAT = "%Y%m%d_%H%M%S";
40 const std::string DEFAULT_TITLE_IMG_PREFIX = "IMG_";
41 const std::string DEFAULT_TITLE_VIDEO_PREFIX = "VID_";
42 const std::string MOVING_PHOTO_VIDEO_EXTENSION = "mp4";
43 std::atomic<uint32_t> MediaAssetChangeRequestImpl::cacheFileId_ = 0;
44 
45 static const std::array<int, 4> ORIENTATION_ARRAY = { 0, 90, 180, 270 };
46 
ReadData(const std::shared_ptr<AVSharedMemory> & mem,uint32_t length)47 int32_t MediaDataSource::ReadData(const std::shared_ptr<AVSharedMemory>& mem, uint32_t length)
48 {
49     if (readPos_ >= size_) {
50         LOGE("Failed to check read position");
51         return SOURCE_ERROR_EOF;
52     }
53 
54     if (memcpy_s(mem->GetBase(), mem->GetSize(), (char*)buffer_ + readPos_, length) != E_OK) {
55         LOGE("Failed to copy buffer to mem");
56         return SOURCE_ERROR_IO;
57     }
58     readPos_ += static_cast<int64_t>(length);
59     return static_cast<int32_t>(length);
60 }
61 
ReadAt(const std::shared_ptr<AVSharedMemory> & mem,uint32_t length,int64_t pos)62 int32_t MediaDataSource::ReadAt(const std::shared_ptr<AVSharedMemory>& mem, uint32_t length, int64_t pos)
63 {
64     readPos_ = pos;
65     return ReadData(mem, length);
66 }
67 
ReadAt(int64_t pos,uint32_t length,const std::shared_ptr<AVSharedMemory> & mem)68 int32_t MediaDataSource::ReadAt(int64_t pos, uint32_t length, const std::shared_ptr<AVSharedMemory>& mem)
69 {
70     readPos_ = pos;
71     return ReadData(mem, length);
72 }
73 
ReadAt(uint32_t length,const std::shared_ptr<AVSharedMemory> & mem)74 int32_t MediaDataSource::ReadAt(uint32_t length, const std::shared_ptr<AVSharedMemory>& mem)
75 {
76     return ReadData(mem, length);
77 }
78 
GetSize(int64_t & size)79 int32_t MediaDataSource::GetSize(int64_t& size)
80 {
81     size = size_;
82     return E_OK;
83 }
84 
GetFileAssetInstance() const85 std::shared_ptr<FileAsset> MediaAssetChangeRequestImpl::GetFileAssetInstance() const
86 {
87     return fileAsset_;
88 }
89 
MediaAssetChangeRequestImpl(std::shared_ptr<FileAsset> fileAssetPtr)90 MediaAssetChangeRequestImpl::MediaAssetChangeRequestImpl(std::shared_ptr<FileAsset> fileAssetPtr)
91 {
92     fileAsset_ = fileAssetPtr;
93 }
94 
ParseFileUri(const std::string & fileUriStr,MediaType mediaType,std::string & realPath)95 static bool ParseFileUri(const std::string& fileUriStr, MediaType mediaType, std::string& realPath)
96 {
97     AppFileService::ModuleFileUri::FileUri fileUri(fileUriStr);
98     std::string path = fileUri.GetRealPath();
99     if (!PathToRealPath(path, realPath)) {
100         return false;
101     }
102     if (mediaType != MediaFileUtils::GetMediaType(realPath)) {
103         return false;
104     }
105     return true;
106 }
107 
CheckMovingPhotoCreationArgs(DataShare::DataShareValuesBucket valuesBucket)108 static bool CheckMovingPhotoCreationArgs(DataShare::DataShareValuesBucket valuesBucket)
109 {
110     bool isValid = false;
111     int32_t mediaType = valuesBucket.Get(MEDIA_DATA_DB_MEDIA_TYPE, isValid);
112     if (!isValid) {
113         return false;
114     }
115     if (mediaType != static_cast<int32_t>(MEDIA_TYPE_IMAGE)) {
116         return false;
117     }
118     std::string extension = valuesBucket.Get(ASSET_EXTENTION, isValid);
119     if (isValid) {
120         return MediaFileUtils::CheckMovingPhotoExtension(extension);
121     }
122 
123     std::string displayName = valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
124     return isValid && MediaFileUtils::CheckMovingPhotoExtension(MediaFileUtils::GetExtensionFromPath(displayName));
125 }
126 
CheckCreateOption(DataShare::DataShareValuesBucket valuesBucket,bool isSystemApi)127 static bool CheckCreateOption(DataShare::DataShareValuesBucket valuesBucket, bool isSystemApi)
128 {
129     bool isValid = false;
130     int32_t subType = valuesBucket.Get(PhotoColumn::PHOTO_SUBTYPE, isValid);
131     if (isValid) {
132         if (subType < static_cast<int32_t>(PhotoSubType::DEFAULT) ||
133             subType >= static_cast<int32_t>(PhotoSubType::SUBTYPE_END)) {
134             return false;
135         }
136         if (subType == static_cast<int32_t>(PhotoSubType::MOVING_PHOTO) &&
137             !CheckMovingPhotoCreationArgs(valuesBucket)) {
138             return false;
139         }
140         if (!isSystemApi && subType != static_cast<int32_t>(PhotoSubType::DEFAULT) &&
141             subType != static_cast<int32_t>(PhotoSubType::MOVING_PHOTO)) {
142             return false;
143         }
144     }
145     std::string cameraShotKey = valuesBucket.Get(PhotoColumn::CAMERA_SHOT_KEY, isValid);
146     if (isValid) {
147         if (cameraShotKey.size() < CAMERA_SHOT_KEY_SIZE) {
148             return false;
149         }
150         if (subType == static_cast<int32_t>(PhotoSubType::SCREENSHOT)) {
151             return false;
152         } else {
153             valuesBucket.Put(PhotoColumn::PHOTO_SUBTYPE, static_cast<int32_t>(PhotoSubType::CAMERA));
154         }
155     }
156     return true;
157 }
158 
MediaAssetChangeRequestImpl(int64_t contextId,int32_t photoType,std::string extension,std::string title,int32_t subType,int32_t * errCode)159 MediaAssetChangeRequestImpl::MediaAssetChangeRequestImpl(
160     int64_t contextId, int32_t photoType, std::string extension, std::string title, int32_t subType, int32_t* errCode)
161 {
162     DataShare::DataShareValuesBucket valuesBucket;
163     if (!MediaAssetChangeRequestImpl::InitUserFileClient(contextId)) {
164         *errCode = JS_INNER_FAIL;
165         return;
166     }
167     MediaType mediaType = static_cast<MediaType>(photoType);
168     if (mediaType != MEDIA_TYPE_IMAGE && mediaType != MEDIA_TYPE_VIDEO &&
169         mediaType != MediaFileUtils::GetMediaType("." + extension)) {
170         LOGE("Invalid photoType or failed to check extension");
171         *errCode = OHOS_INVALID_PARAM_CODE;
172         return;
173     }
174     valuesBucket.Put(ASSET_EXTENTION, extension);
175     valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, static_cast<int32_t>(mediaType));
176     if (!title.empty()) {
177         valuesBucket.Put(PhotoColumn::MEDIA_TITLE, title);
178     }
179     if (subType != -1) {
180         valuesBucket.Put(PhotoColumn::PHOTO_SUBTYPE, subType);
181     }
182     if (!CheckCreateOption(valuesBucket, false)) {
183         *errCode = OHOS_INVALID_PARAM_CODE;
184         return;
185     }
186     bool isValid = false;
187     std::string newTitle = valuesBucket.Get(PhotoColumn::MEDIA_TITLE, isValid);
188     if (!isValid) {
189         newTitle = mediaType == MEDIA_TYPE_IMAGE ? DEFAULT_TITLE_IMG_PREFIX : DEFAULT_TITLE_VIDEO_PREFIX;
190         newTitle += MediaFileUtils::StrCreateTime(DEFAULT_TITLE_TIME_FORMAT, MediaFileUtils::UTCTimeSeconds());
191         valuesBucket.Put(PhotoColumn::MEDIA_TITLE, newTitle);
192     }
193     std::string displayName = newTitle + "." + extension;
194     if (MediaFileUtils::CheckDisplayName(displayName) != E_OK) {
195         *errCode = OHOS_INVALID_PARAM_CODE;
196         return;
197     }
198     valuesBucket.Put(MEDIA_DATA_DB_NAME, displayName);
199     auto emptyFileAsset = std::make_unique<FileAsset>();
200     emptyFileAsset->SetDisplayName(displayName);
201     emptyFileAsset->SetTitle(MediaFileUtils::GetTitleFromDisplayName(displayName));
202     emptyFileAsset->SetMediaType(MediaFileUtils::GetMediaType(displayName));
203     emptyFileAsset->SetPhotoSubType(subType);
204     emptyFileAsset->SetTimePending(CREATE_ASSET_REQUEST_PENDING);
205     emptyFileAsset->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
206     fileAsset_ = std::move(emptyFileAsset);
207     creationValuesBucket_ = std::move(valuesBucket);
208     RecordChangeOperation(AssetChangeOperation::CREATE_FROM_SCRATCH);
209 }
210 
ParseArgsDeleteAssets(int64_t contextId,std::vector<std::string> uris)211 static int32_t ParseArgsDeleteAssets(int64_t contextId, std::vector<std::string> uris)
212 {
213     if (!MediaAssetChangeRequestImpl::InitUserFileClient(contextId)) {
214         return JS_INNER_FAIL;
215     }
216     if (uris.empty()) {
217         LOGE("Failed to check empty array");
218         return OHOS_INVALID_PARAM_CODE;
219     }
220     for (const auto& uri : uris) {
221         if (uri.find(PhotoColumn::PHOTO_URI_PREFIX) == std::string::npos) {
222             return JS_E_URI;
223         }
224     }
225     return 0;
226 }
227 
GetAssetChangeOperations() const228 std::vector<AssetChangeOperation> MediaAssetChangeRequestImpl::GetAssetChangeOperations() const
229 {
230     return assetChangeOperations_;
231 }
232 
GetAddResourceTypes() const233 std::vector<ResourceType> MediaAssetChangeRequestImpl::GetAddResourceTypes() const
234 {
235     return addResourceTypes_;
236 }
237 
HasWritePermission()238 static bool HasWritePermission()
239 {
240     AccessTokenID tokenCaller = IPCSkeleton::GetSelfTokenID();
241     int result = AccessTokenKit::VerifyAccessToken(tokenCaller, PERM_WRITE_IMAGEVIDEO);
242     return result == PermissionState::PERMISSION_GRANTED;
243 }
244 
InitDeleteRequest(std::string & appName,std::vector<std::string> & uris,OHOS::AAFwk::Want & request,std::shared_ptr<DeleteCallback> & callback)245 static bool InitDeleteRequest(std::string& appName, std::vector<std::string>& uris, OHOS::AAFwk::Want& request,
246     std::shared_ptr<DeleteCallback>& callback)
247 {
248     request.SetElementName(DELETE_UI_PACKAGE_NAME, DELETE_UI_EXT_ABILITY_NAME);
249     request.SetParam(DELETE_UI_EXTENSION_TYPE, DELETE_UI_REQUEST_TYPE);
250 
251     if (appName.empty()) {
252         return false;
253     }
254     request.SetParam(DELETE_UI_APPNAME, appName);
255 
256     request.SetParam(DELETE_UI_URIS, uris);
257     callback->SetUris(uris);
258     return true;
259 }
260 
DeleteAssetsExecute(OHOS::DataShare::DataSharePredicates & predicates,OHOS::DataShare::DataShareValuesBucket & valuesBucket)261 static int32_t DeleteAssetsExecute(OHOS::DataShare::DataSharePredicates& predicates,
262     OHOS::DataShare::DataShareValuesBucket& valuesBucket)
263 {
264     std::string trashUri = PAH_SYS_TRASH_PHOTO;
265     MediaLibraryNapiUtils::UriAppendKeyValue(trashUri, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
266     Uri updateAssetUri(trashUri);
267     int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
268     if (changedRows < 0) {
269         LOGE("Failed to delete assets, err: %{public}d", changedRows);
270         return changedRows;
271     }
272     return 0;
273 }
274 
SetSessionId(std::string & appName,std::vector<std::string> & uris,Ace::UIContent * uiContent,std::shared_ptr<DeleteCallback> & callback,Ace::ModalUIExtensionCallbacks & extensionCallback)275 static int32_t SetSessionId(std::string &appName, std::vector<std::string> &uris, Ace::UIContent* uiContent,
276     std::shared_ptr<DeleteCallback>& callback, Ace::ModalUIExtensionCallbacks &extensionCallback)
277 {
278     OHOS::AAFwk::Want request;
279     if (!InitDeleteRequest(appName, uris, request, callback)) {
280         return JS_INNER_FAIL;
281     }
282     OHOS::Ace::ModalUIExtensionConfig config;
283     config.isProhibitBack = true;
284     int32_t sessionId = uiContent->CreateModalUIExtension(request, extensionCallback, config);
285     if (sessionId == 0) {
286         return JS_INNER_FAIL;
287     }
288     callback->SetSessionId(sessionId);
289     return 0;
290 }
291 
CJDeleteAssets(int64_t contextId,std::vector<std::string> uris)292 int32_t MediaAssetChangeRequestImpl::CJDeleteAssets(int64_t contextId, std::vector<std::string> uris)
293 {
294     if (ParseArgsDeleteAssets(contextId, uris) != 0) {
295         return OHOS_INVALID_PARAM_CODE;
296     }
297     OHOS::DataShare::DataSharePredicates predicates;
298     OHOS::DataShare::DataShareValuesBucket valuesBucket;
299     predicates.In(PhotoColumn::MEDIA_ID, uris);
300     valuesBucket.Put(PhotoColumn::MEDIA_DATE_TRASHED, MediaFileUtils::UTCTimeSeconds());
301     if (MediaLibraryNapiUtils::IsSystemApp()) {
302         DeleteAssetsExecute(predicates, valuesBucket);
303     }
304 #ifdef HAS_ACE_ENGINE_PART
305     if (!HasWritePermission()) {
306         return OHOS_PERMISSION_DENIED_CODE;
307     }
308     if (uris.size() > MAX_DELETE_NUMBER) {
309         LOGE("No more than 300 assets can be deleted at one time");
310         return OHOS_INVALID_PARAM_CODE;
311     }
312     auto cjAbilityContext = FFI::FFIData::GetData<AbilityRuntime::CJAbilityContext>(contextId);
313     if (cjAbilityContext == nullptr || cjAbilityContext->GetAbilityContext() == nullptr) {
314         LOGE("Failed to get native stage context instance");
315         return JS_INNER_FAIL;
316     }
317     auto abilityContext = cjAbilityContext->GetAbilityContext();
318     auto abilityInfo = abilityContext->GetAbilityInfo();
319     std::string appName;
320     abilityContext->GetResourceManager()->GetStringById(abilityInfo->labelId, appName);
321     auto uiContent = abilityContext->GetUIContent();
322     if (uiContent == nullptr) {
323         return JS_INNER_FAIL;
324     }
325     auto callback = std::make_shared<DeleteCallback>(uiContent);
326     OHOS::Ace::ModalUIExtensionCallbacks extensionCallback = {
327         [callback](int32_t releaseCode) { callback->OnRelease(releaseCode); },
328         [callback](int32_t resultCode, const AAFwk::Want& result) { callback->OnResult(resultCode, result); },
329         [callback](const OHOS::AAFwk::WantParams& request) { callback->OnReceive(request); },
330         [callback](int32_t code, const std::string& name, const std::string& message) {
331             callback->OnError(code, name, message);
332         },
333     };
334     return SetSessionId(appName, uris, uiContent, callback, extensionCallback);
335 #else
336     LOGE("ace_engine is not support");
337     return JS_INNER_FAIL;
338 #endif
339 }
340 
CJGetAsset(int32_t * errCode)341 int64_t MediaAssetChangeRequestImpl::CJGetAsset(int32_t* errCode)
342 {
343     if (fileAsset_ == nullptr) {
344         *errCode = JS_INNER_FAIL;
345         return 0;
346     }
347     if (fileAsset_->GetId() > 0) {
348         auto photoAssetImpl = FFIData::Create<PhotoAssetImpl>(fileAsset_);
349         if (!photoAssetImpl) {
350             *errCode = JS_INNER_FAIL;
351             return 0;
352         }
353         return photoAssetImpl->GetID();
354     }
355     return 0;
356 }
357 
MediaAssetChangeRequestImpl(int64_t contextId,const std::string & filePath,MediaType meidiaType,int32_t * errCode)358 MediaAssetChangeRequestImpl::MediaAssetChangeRequestImpl(
359     int64_t contextId, const std::string& filePath, MediaType meidiaType, int32_t* errCode)
360 {
361     if (!MediaAssetChangeRequestImpl::InitUserFileClient(contextId)) {
362         *errCode = JS_INNER_FAIL;
363         return;
364     }
365     std::string realPath;
366     if ((meidiaType == MediaType::MEDIA_TYPE_IMAGE && ParseFileUri(filePath, MediaType::MEDIA_TYPE_IMAGE, realPath)) ||
367         (meidiaType == MediaType::MEDIA_TYPE_VIDEO && ParseFileUri(filePath, MediaType::MEDIA_TYPE_VIDEO, realPath))) {
368         std::string displayName = MediaFileUtils::GetFileName(realPath);
369         if (MediaFileUtils::CheckDisplayName(displayName) != E_OK) {
370             *errCode = OHOS_INVALID_PARAM_CODE;
371             return;
372         }
373         std::string title = MediaFileUtils::GetTitleFromDisplayName(displayName);
374         MediaType mediaType = MediaFileUtils::GetMediaType(displayName);
375         auto emptyFileAsset = std::make_unique<FileAsset>();
376         emptyFileAsset->SetDisplayName(displayName);
377         emptyFileAsset->SetTitle(title);
378         emptyFileAsset->SetMediaType(mediaType);
379         emptyFileAsset->SetPhotoSubType(static_cast<int32_t>(PhotoSubType::DEFAULT));
380         emptyFileAsset->SetTimePending(CREATE_ASSET_REQUEST_PENDING);
381         emptyFileAsset->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
382         fileAsset_ = std::move(emptyFileAsset);
383         realPath_ = realPath;
384         creationValuesBucket_.Put(MEDIA_DATA_DB_NAME, displayName);
385         creationValuesBucket_.Put(ASSET_EXTENTION, MediaFileUtils::GetExtensionFromPath(displayName));
386         creationValuesBucket_.Put(MEDIA_DATA_DB_MEDIA_TYPE, static_cast<int32_t>(mediaType));
387         creationValuesBucket_.Put(PhotoColumn::MEDIA_TITLE, title);
388         RecordChangeOperation(AssetChangeOperation::CREATE_FROM_URI);
389         return;
390     }
391     *errCode = OHOS_INVALID_PARAM_CODE;
392     return;
393 }
394 
RecordChangeOperation(AssetChangeOperation changeOperation)395 void MediaAssetChangeRequestImpl::RecordChangeOperation(AssetChangeOperation changeOperation)
396 {
397     if ((changeOperation == AssetChangeOperation::GET_WRITE_CACHE_HANDLER ||
398             changeOperation == AssetChangeOperation::ADD_RESOURCE ||
399             changeOperation == AssetChangeOperation::ADD_FILTERS) &&
400         Contains(AssetChangeOperation::CREATE_FROM_SCRATCH)) {
401         assetChangeOperations_.insert(assetChangeOperations_.begin() + 1, changeOperation);
402         return;
403     }
404     if (changeOperation == AssetChangeOperation::ADD_RESOURCE &&
405         Contains(AssetChangeOperation::SET_MOVING_PHOTO_EFFECT_MODE)) {
406         assetChangeOperations_.insert(assetChangeOperations_.begin(), changeOperation);
407         return;
408     }
409     assetChangeOperations_.push_back(changeOperation);
410 }
411 
Contains(AssetChangeOperation changeOperation) const412 bool MediaAssetChangeRequestImpl::Contains(AssetChangeOperation changeOperation) const
413 {
414     return std::find(assetChangeOperations_.begin(), assetChangeOperations_.end(), changeOperation) !=
415            assetChangeOperations_.end();
416 }
417 
FetchAddCacheFileId()418 uint32_t MediaAssetChangeRequestImpl::FetchAddCacheFileId()
419 {
420     uint32_t id = cacheFileId_.fetch_add(1);
421     return id;
422 }
423 
SetCacheFileName(std::string & fileName)424 void MediaAssetChangeRequestImpl::SetCacheFileName(std::string& fileName)
425 {
426     cacheFileName_ = fileName;
427 }
428 
SetCacheMovingPhotoVideoName(std::string & fileName)429 void MediaAssetChangeRequestImpl::SetCacheMovingPhotoVideoName(std::string& fileName)
430 {
431     cacheMovingPhotoVideoName_ = fileName;
432 }
433 
GetMovingPhotoVideoPath() const434 std::string MediaAssetChangeRequestImpl::GetMovingPhotoVideoPath() const
435 {
436     return movingPhotoVideoRealPath_;
437 }
438 
GetFileRealPath() const439 std::string MediaAssetChangeRequestImpl::GetFileRealPath() const
440 {
441     return realPath_;
442 }
443 
GetAddResourceMode() const444 AddResourceMode MediaAssetChangeRequestImpl::GetAddResourceMode() const
445 {
446     return addResourceMode_;
447 }
448 
GetDataBuffer() const449 void* MediaAssetChangeRequestImpl::GetDataBuffer() const
450 {
451     return dataBuffer_;
452 }
453 
GetDataBufferSize() const454 size_t MediaAssetChangeRequestImpl::GetDataBufferSize() const
455 {
456     return dataBufferSize_;
457 }
458 
GetMovingPhotoVideoMode() const459 AddResourceMode MediaAssetChangeRequestImpl::GetMovingPhotoVideoMode() const
460 {
461     return movingPhotoVideoResourceMode_;
462 }
463 
GetMovingPhotoVideoBuffer() const464 void* MediaAssetChangeRequestImpl::GetMovingPhotoVideoBuffer() const
465 {
466     return movingPhotoVideoDataBuffer_;
467 }
468 
GetMovingPhotoVideoSize() const469 size_t MediaAssetChangeRequestImpl::GetMovingPhotoVideoSize() const
470 {
471     return movingPhotoVideoBufferSize_;
472 }
473 
GetPhotoProxyObj()474 sptr<PhotoProxy> MediaAssetChangeRequestImpl::GetPhotoProxyObj()
475 {
476     return photoProxy_;
477 }
478 
ReleasePhotoProxyObj()479 void MediaAssetChangeRequestImpl::ReleasePhotoProxyObj()
480 {
481     photoProxy_->Release();
482     photoProxy_ = nullptr;
483 }
484 
GetImageFileType()485 int32_t MediaAssetChangeRequestImpl::GetImageFileType()
486 {
487     return imageFileType_;
488 }
489 
CreateAssetBySecurityComponent(std::string & assetUri)490 int32_t MediaAssetChangeRequestImpl::CreateAssetBySecurityComponent(std::string& assetUri)
491 {
492     bool isValid = false;
493     std::string title = creationValuesBucket_.Get(PhotoColumn::MEDIA_TITLE, isValid);
494     if (!isValid) {
495         LOGE("Failed to get title");
496         return E_FAIL;
497     }
498     std::string extension = creationValuesBucket_.Get(ASSET_EXTENTION, isValid);
499     if (!isValid || MediaFileUtils::CheckDisplayName(title + "." + extension) != E_OK) {
500         LOGE("Failed to check displayName");
501         return E_FAIL;
502     }
503     creationValuesBucket_.valuesMap.erase(MEDIA_DATA_DB_NAME);
504 
505     std::string uri = PAH_CREATE_PHOTO_COMPONENT; // create asset by security component
506     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
507     Uri createAssetUri(uri);
508     return UserFileClient::InsertExt(createAssetUri, creationValuesBucket_, assetUri);
509 }
510 
PutMediaAssetEditData(DataShare::DataShareValuesBucket & valuesBucket)511 int32_t MediaAssetChangeRequestImpl::PutMediaAssetEditData(DataShare::DataShareValuesBucket& valuesBucket)
512 {
513     if (editData_ == nullptr) {
514         return E_OK;
515     }
516 
517     std::string compatibleFormat = editData_->GetCompatibleFormat();
518     if (compatibleFormat.empty()) {
519         LOGE("Failed to check compatibleFormat");
520         return E_FAIL;
521     }
522     std::string formatVersion = editData_->GetFormatVersion();
523     if (formatVersion.empty()) {
524         LOGE("Failed to check formatVersion");
525         return E_FAIL;
526     }
527     std::string data = editData_->GetData();
528     if (data.empty()) {
529         LOGE("Failed to check data");
530         return E_FAIL;
531     }
532 
533     valuesBucket.Put(COMPATIBLE_FORMAT, compatibleFormat);
534     valuesBucket.Put(FORMAT_VERSION, formatVersion);
535     valuesBucket.Put(EDIT_DATA, data);
536     return E_OK;
537 }
538 
CopyToMediaLibrary(bool isCreation,AddResourceMode mode)539 int32_t MediaAssetChangeRequestImpl::CopyToMediaLibrary(bool isCreation, AddResourceMode mode)
540 {
541     if (fileAsset_ == nullptr) {
542         LOGE("Failed to check fileAsset_");
543         return E_FAIL;
544     }
545     int32_t ret = E_ERR;
546     int32_t id = 0;
547     std::string assetUri;
548     if (isCreation) {
549         ret = CreateAssetBySecurityComponent(assetUri);
550         if (ret <= 0) {
551             LOGE("Failed to create asset by security component");
552             return ret == 0 ? E_ERR : ret;
553         }
554         id = ret;
555     } else {
556         assetUri = fileAsset_->GetUri();
557     }
558     if (assetUri.empty()) {
559         LOGE("Failed to check empty asset uri");
560         return E_ERR;
561     }
562 
563     if (IsMovingPhoto()) {
564         ret = CopyMovingPhotoVideo(assetUri);
565         if (ret != E_OK) {
566             LOGE("Failed to copy data to moving photo video with error: %{public}d", ret);
567             return ret;
568         }
569     }
570 
571     Uri uri(assetUri);
572     UniqueFd destFd(UserFileClient::OpenFile(uri, MEDIA_FILEMODE_WRITEONLY));
573     if (destFd.Get() < 0) {
574         LOGE("Failed to open %{private}s with error: %{public}d", assetUri.c_str(), destFd.Get());
575         return destFd.Get();
576     }
577 
578     if (mode == AddResourceMode::FILE_URI) {
579         ret = CopyFileToMediaLibrary(destFd);
580     } else if (mode == AddResourceMode::DATA_BUFFER) {
581         ret = CopyDataBufferToMediaLibrary(destFd);
582     } else {
583         LOGE("Invalid mode: %{public}d", mode);
584         return E_INVALID_VALUES;
585     }
586 
587     if (ret == E_OK && isCreation) {
588         SetNewFileAsset(id, assetUri);
589     }
590     return ret;
591 }
592 
ContainsResource(ResourceType resourceType) const593 bool MediaAssetChangeRequestImpl::ContainsResource(ResourceType resourceType) const
594 {
595     return std::find(addResourceTypes_.begin(), addResourceTypes_.end(), resourceType) != addResourceTypes_.end();
596 }
597 
IsMovingPhoto() const598 bool MediaAssetChangeRequestImpl::IsMovingPhoto() const
599 {
600     return fileAsset_ != nullptr &&
601            (fileAsset_->GetPhotoSubType() == static_cast<int32_t>(PhotoSubType::MOVING_PHOTO) ||
602                (fileAsset_->GetPhotoSubType() == static_cast<int32_t>(PhotoSubType::DEFAULT) &&
603                    fileAsset_->GetMovingPhotoEffectMode() == static_cast<int32_t>(MovingPhotoEffectMode::IMAGE_ONLY)));
604 }
605 
CheckMovingPhotoResource(ResourceType resourceType) const606 bool MediaAssetChangeRequestImpl::CheckMovingPhotoResource(ResourceType resourceType) const
607 {
608     if (resourceType == ResourceType::INVALID_RESOURCE) {
609         LOGE("Invalid resource type");
610         return false;
611     }
612 
613     bool isResourceTypeVaild = !ContainsResource(resourceType);
614     int addResourceTimes =
615         std::count(assetChangeOperations_.begin(), assetChangeOperations_.end(), AssetChangeOperation::ADD_RESOURCE);
616     return isResourceTypeVaild && addResourceTimes <= 1; // currently, add resource no more than once
617 }
618 
619 static const std::unordered_map<MovingPhotoEffectMode, std::unordered_map<ResourceType, bool>>
620     EFFECT_MODE_RESOURCE_CHECK = {
621         { MovingPhotoEffectMode::DEFAULT,
622             { { ResourceType::IMAGE_RESOURCE, false }, { ResourceType::VIDEO_RESOURCE, false } } },
623         { MovingPhotoEffectMode::BOUNCE_PLAY,
624             { { ResourceType::IMAGE_RESOURCE, false }, { ResourceType::VIDEO_RESOURCE, true } } },
625         { MovingPhotoEffectMode::LOOP_PLAY,
626             { { ResourceType::IMAGE_RESOURCE, false }, { ResourceType::VIDEO_RESOURCE, true } } },
627         { MovingPhotoEffectMode::CINEMA_GRAPH,
628             { { ResourceType::IMAGE_RESOURCE, false }, { ResourceType::VIDEO_RESOURCE, true } } },
629         { MovingPhotoEffectMode::LONG_EXPOSURE,
630             { { ResourceType::IMAGE_RESOURCE, true }, { ResourceType::VIDEO_RESOURCE, false } } },
631         { MovingPhotoEffectMode::MULTI_EXPOSURE,
632             { { ResourceType::IMAGE_RESOURCE, true }, { ResourceType::VIDEO_RESOURCE, false } } },
633         { MovingPhotoEffectMode::IMAGE_ONLY,
634             { { ResourceType::IMAGE_RESOURCE, false }, { ResourceType::VIDEO_RESOURCE, false } } },
635     };
636 
CheckEffectModeWriteOperation()637 bool MediaAssetChangeRequestImpl::CheckEffectModeWriteOperation()
638 {
639     if (fileAsset_ == nullptr) {
640         LOGE("fileAsset is nullptr");
641         return false;
642     }
643 
644     if (fileAsset_->GetTimePending() != 0) {
645         LOGE("Failed to check pending of fileAsset: %{public}" PRId64, fileAsset_->GetTimePending());
646         return false;
647     }
648 
649     MovingPhotoEffectMode effectMode = static_cast<MovingPhotoEffectMode>(fileAsset_->GetMovingPhotoEffectMode());
650     auto iter = EFFECT_MODE_RESOURCE_CHECK.find(effectMode);
651     if (iter == EFFECT_MODE_RESOURCE_CHECK.end()) {
652         LOGE("Failed to check effect mode: %{public}d", static_cast<int32_t>(effectMode));
653         return false;
654     }
655 
656     bool isImageExist = ContainsResource(ResourceType::IMAGE_RESOURCE);
657     bool isVideoExist = ContainsResource(ResourceType::VIDEO_RESOURCE);
658     if (iter->second.at(ResourceType::IMAGE_RESOURCE) && !isImageExist) {
659         LOGE("Failed to check image resource for effect mode: %{public}d", static_cast<int32_t>(effectMode));
660         return false;
661     }
662     if (iter->second.at(ResourceType::VIDEO_RESOURCE) && !isVideoExist) {
663         LOGE("Failed to check video resource for effect mode: %{public}d", static_cast<int32_t>(effectMode));
664         return false;
665     }
666     return true;
667 }
668 
CheckMovingPhotoWriteOperation()669 bool MediaAssetChangeRequestImpl::CheckMovingPhotoWriteOperation()
670 {
671     if (Contains(AssetChangeOperation::SET_MOVING_PHOTO_EFFECT_MODE)) {
672         return CheckEffectModeWriteOperation();
673     }
674 
675     bool containsAddResource = Contains(AssetChangeOperation::ADD_RESOURCE);
676     if (!containsAddResource) {
677         return true;
678     }
679 
680     bool isCreation = Contains(AssetChangeOperation::CREATE_FROM_SCRATCH);
681     if (!isCreation) {
682         return true;
683     }
684 
685     int addResourceTimes =
686         std::count(assetChangeOperations_.begin(), assetChangeOperations_.end(), AssetChangeOperation::ADD_RESOURCE);
687     bool isImageExist = ContainsResource(ResourceType::IMAGE_RESOURCE);
688     bool isVideoExist = ContainsResource(ResourceType::VIDEO_RESOURCE);
689     return addResourceTimes == 2 && isImageExist && isVideoExist; // must add resource 2 times with image and video
690 }
691 
CheckChangeOperations()692 bool MediaAssetChangeRequestImpl::CheckChangeOperations()
693 {
694     if (assetChangeOperations_.empty()) {
695         LOGE("None request to apply");
696         return false;
697     }
698 
699     bool isCreateFromScratch = Contains(AssetChangeOperation::CREATE_FROM_SCRATCH);
700     bool isCreateFromUri = Contains(AssetChangeOperation::CREATE_FROM_URI);
701     bool containsEdit = Contains(AssetChangeOperation::SET_EDIT_DATA);
702     bool containsGetHandler = Contains(AssetChangeOperation::GET_WRITE_CACHE_HANDLER);
703     bool containsAddResource = Contains(AssetChangeOperation::ADD_RESOURCE);
704     bool isSaveCameraPhoto = Contains(AssetChangeOperation::SAVE_CAMERA_PHOTO);
705     if ((isCreateFromScratch || containsEdit) && !containsGetHandler && !containsAddResource && !isSaveCameraPhoto) {
706         LOGE("Cannot create or edit asset without data to write");
707         return false;
708     }
709 
710     if (containsEdit && (isCreateFromScratch || isCreateFromUri)) {
711         LOGE("Cannot create together with edit");
712         return false;
713     }
714 
715     auto fileAsset = GetFileAssetInstance();
716     if (fileAsset == nullptr) {
717         LOGE("fileAsset is null");
718         return false;
719     }
720 
721     AssetChangeOperation firstOperation = assetChangeOperations_.front();
722     if (fileAsset->GetId() <= 0 && firstOperation != AssetChangeOperation::CREATE_FROM_SCRATCH &&
723         firstOperation != AssetChangeOperation::CREATE_FROM_URI) {
724         LOGE("Invalid asset change request");
725         return false;
726     }
727 
728     bool isMovingPhoto = IsMovingPhoto();
729     if (isMovingPhoto && !CheckMovingPhotoWriteOperation()) {
730         LOGE("Invalid write operation for moving photo");
731         return false;
732     }
733 
734     return true;
735 }
736 
SendFile(const UniqueFd & srcFd,const UniqueFd & destFd)737 static int32_t SendFile(const UniqueFd& srcFd, const UniqueFd& destFd)
738 {
739     if (srcFd.Get() < 0 || destFd.Get() < 0) {
740         LOGE("Failed to check srcFd: %{public}d and destFd: %{public}d", srcFd.Get(), destFd.Get());
741         return E_ERR;
742     }
743 
744     struct stat statSrc {};
745     int32_t status = fstat(srcFd.Get(), &statSrc);
746     if (status != 0) {
747         LOGE("Failed to get file stat, errno=%{public}d", errno);
748         return status;
749     }
750 
751     off_t offset = 0;
752     off_t fileSize = statSrc.st_size;
753     while (offset < fileSize) {
754         ssize_t sent = sendfile(destFd.Get(), srcFd.Get(), &offset, fileSize - offset);
755         if (sent < 0) {
756             LOGE("Failed to sendfile with errno=%{public}d, srcFd=%{private}d, destFd=%{private}d", errno, srcFd.Get(),
757                 destFd.Get());
758             return sent;
759         }
760     }
761 
762     return E_OK;
763 }
764 
CopyFileToMediaLibrary(const UniqueFd & destFd,bool isMovingPhotoVideo)765 int32_t MediaAssetChangeRequestImpl::CopyFileToMediaLibrary(const UniqueFd& destFd, bool isMovingPhotoVideo)
766 {
767     std::string srcRealPath = isMovingPhotoVideo ? movingPhotoVideoRealPath_ : realPath_;
768     if (srcRealPath.empty()) {
769         LOGE("Failed to check real path of source");
770         return E_FAIL;
771     }
772 
773     std::string absFilePath;
774     if (!PathToRealPath(srcRealPath, absFilePath)) {
775         LOGE("Not real path %{private}s", srcRealPath.c_str());
776         return E_FAIL;
777     }
778     UniqueFd srcFd(open(absFilePath.c_str(), O_RDONLY));
779     if (srcFd.Get() < 0) {
780         LOGE("Failed to open %{private}s, errno=%{public}d", absFilePath.c_str(), errno);
781         return srcFd.Get();
782     }
783 
784     int32_t err = SendFile(srcFd, destFd);
785     if (err != E_OK) {
786         LOGE("Failed to send file from %{public}d to %{public}d", srcFd.Get(), destFd.Get());
787     }
788     return err;
789 }
790 
CopyDataBufferToMediaLibrary(const UniqueFd & destFd,bool isMovingPhotoVideo)791 int32_t MediaAssetChangeRequestImpl::CopyDataBufferToMediaLibrary(const UniqueFd& destFd, bool isMovingPhotoVideo)
792 {
793     size_t offset = 0;
794     size_t length = isMovingPhotoVideo ? movingPhotoVideoBufferSize_ : dataBufferSize_;
795     void* dataBuffer = isMovingPhotoVideo ? movingPhotoVideoDataBuffer_ : dataBuffer_;
796     while (offset < length) {
797         ssize_t written = write(destFd.Get(), (char*)dataBuffer + offset, length - offset);
798         if (written < 0) {
799             LOGE("Failed to copy data buffer, return %{public}d", static_cast<int>(written));
800             return written;
801         }
802         offset += static_cast<size_t>(written);
803     }
804     return E_OK;
805 }
806 
CopyMovingPhotoVideo(const std::string & assetUri)807 int32_t MediaAssetChangeRequestImpl::CopyMovingPhotoVideo(const std::string& assetUri)
808 {
809     if (assetUri.empty()) {
810         LOGE("Failed to check empty asset uri");
811         return E_INVALID_URI;
812     }
813 
814     std::string videoUri = assetUri;
815     MediaFileUtils::UriAppendKeyValue(videoUri, MEDIA_MOVING_PHOTO_OPRN_KEYWORD, OPEN_MOVING_PHOTO_VIDEO);
816     Uri uri(videoUri);
817     int videoFd = UserFileClient::OpenFile(uri, MEDIA_FILEMODE_WRITEONLY);
818     if (videoFd < 0) {
819         LOGE("Failed to open video of moving photo with write-only mode");
820         return videoFd;
821     }
822 
823     int32_t ret = E_ERR;
824     UniqueFd uniqueFd(videoFd);
825     if (movingPhotoVideoResourceMode_ == AddResourceMode::FILE_URI) {
826         ret = CopyFileToMediaLibrary(uniqueFd, true);
827     } else if (movingPhotoVideoResourceMode_ == AddResourceMode::DATA_BUFFER) {
828         ret = CopyDataBufferToMediaLibrary(uniqueFd, true);
829     } else {
830         LOGE("Invalid mode: %{public}d", movingPhotoVideoResourceMode_);
831         return E_INVALID_VALUES;
832     }
833     return ret;
834 }
835 
SetNewFileAsset(int32_t id,const std::string & uri)836 void MediaAssetChangeRequestImpl::SetNewFileAsset(int32_t id, const std::string& uri)
837 {
838     if (fileAsset_ == nullptr) {
839         LOGE("fileAsset_ is nullptr");
840         return;
841     }
842 
843     if (id <= 0 || uri.empty()) {
844         LOGE("Failed to check file_id: %{public}d and uri: %{public}s", id, uri.c_str());
845         return;
846     }
847     fileAsset_->SetId(id);
848     fileAsset_->SetUri(uri);
849     fileAsset_->SetTimePending(0);
850 }
851 
CJSetTitle(std::string title)852 int32_t MediaAssetChangeRequestImpl::CJSetTitle(std::string title)
853 {
854     if (fileAsset_ == nullptr) {
855         return JS_INNER_FAIL;
856     }
857     std::string extension = MediaFileUtils::SplitByChar(fileAsset_->GetDisplayName(), '.');
858     std::string displayName = title + "." + extension;
859     if (MediaFileUtils::CheckDisplayName(displayName) != E_OK) {
860         return OHOS_INVALID_PARAM_CODE;
861     }
862     fileAsset_->SetTitle(title);
863     fileAsset_->SetDisplayName(displayName);
864     RecordChangeOperation(AssetChangeOperation::SET_TITLE);
865     if (Contains(AssetChangeOperation::CREATE_FROM_SCRATCH) || Contains(AssetChangeOperation::CREATE_FROM_URI)) {
866         creationValuesBucket_.valuesMap[MEDIA_DATA_DB_NAME] = displayName;
867         creationValuesBucket_.valuesMap[PhotoColumn::MEDIA_TITLE] = title;
868     }
869     return 0;
870 }
871 
OpenWriteCacheHandler(MediaAssetChangeRequestImpl * changeRequest,bool isMovingPhotoVideo=false)872 static int32_t OpenWriteCacheHandler(MediaAssetChangeRequestImpl* changeRequest, bool isMovingPhotoVideo = false)
873 {
874     auto fileAsset = changeRequest->GetFileAssetInstance();
875     if (fileAsset == nullptr) {
876         return E_FAIL;
877     }
878     std::string extension = isMovingPhotoVideo ? MOVING_PHOTO_VIDEO_EXTENSION
879                                                : MediaFileUtils::GetExtensionFromPath(fileAsset->GetDisplayName());
880     int64_t currentTimestamp = MediaFileUtils::UTCTimeNanoSeconds();
881     uint32_t cacheFileId = changeRequest->FetchAddCacheFileId();
882     std::string cacheFileName = std::to_string(currentTimestamp) + "_" + std::to_string(cacheFileId) + "." + extension;
883     std::string uri = PhotoColumn::PHOTO_CACHE_URI_PREFIX + cacheFileName;
884     MediaFileUtils::UriAppendKeyValue(uri, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
885     Uri openCacheUri(uri);
886     int32_t ret = UserFileClient::OpenFile(openCacheUri, MEDIA_FILEMODE_WRITEONLY);
887     if (ret == E_PERMISSION_DENIED) {
888         LOGE("Open cache file failed, permission denied");
889         return OHOS_PERMISSION_DENIED_CODE;
890     }
891     if (ret < 0) {
892         LOGE("Open cache file failed, ret: %{public}d", ret);
893     }
894 
895     if (isMovingPhotoVideo) {
896         changeRequest->SetCacheMovingPhotoVideoName(cacheFileName);
897     } else {
898         changeRequest->SetCacheFileName(cacheFileName);
899     }
900     return ret;
901 }
902 
CJGetWriteCacheHandler(int32_t * errCode)903 int32_t MediaAssetChangeRequestImpl::CJGetWriteCacheHandler(int32_t* errCode)
904 {
905     if (fileAsset_ == nullptr) {
906         *errCode = JS_INNER_FAIL;
907         return 0;
908     }
909     if (IsMovingPhoto()) {
910         *errCode = JS_E_OPERATION_NOT_SUPPORT;
911         return 0;
912     }
913     if (Contains(AssetChangeOperation::CREATE_FROM_URI) || Contains(AssetChangeOperation::GET_WRITE_CACHE_HANDLER) ||
914         Contains(AssetChangeOperation::ADD_RESOURCE)) {
915         *errCode = JS_E_OPERATION_NOT_SUPPORT;
916         return 0;
917     }
918     int32_t ret = OpenWriteCacheHandler(this);
919     if (ret < 0) {
920         LOGE("Failed to open write cache handler, ret: %{public}d", ret);
921         *errCode = ret;
922         return 0;
923     }
924     RecordChangeOperation(AssetChangeOperation::GET_WRITE_CACHE_HANDLER);
925     return ret;
926 }
927 
CheckWriteOperation(MediaAssetChangeRequestImpl * changeRequest,ResourceType resourceType=ResourceType::INVALID_RESOURCE)928 static int32_t CheckWriteOperation(
929     MediaAssetChangeRequestImpl* changeRequest, ResourceType resourceType = ResourceType::INVALID_RESOURCE)
930 {
931     if (changeRequest == nullptr) {
932         LOGE("changeRequest is null");
933         return OHOS_INVALID_PARAM_CODE;
934     }
935 
936     if (changeRequest->IsMovingPhoto()) {
937         if (!changeRequest->CheckMovingPhotoResource(resourceType)) {
938             LOGE("Failed to check resource to add for moving photo");
939             return OHOS_INVALID_PARAM_CODE;
940         }
941         return 0;
942     }
943 
944     if (changeRequest->Contains(AssetChangeOperation::CREATE_FROM_URI) ||
945         changeRequest->Contains(AssetChangeOperation::GET_WRITE_CACHE_HANDLER) ||
946         changeRequest->Contains(AssetChangeOperation::ADD_RESOURCE)) {
947         LOGE("The previous asset creation/modification request has not been applied");
948         return JS_E_OPERATION_NOT_SUPPORT;
949     }
950     return 0;
951 }
952 
GetResourceType(int32_t value)953 static ResourceType GetResourceType(int32_t value)
954 {
955     ResourceType result = ResourceType::INVALID_RESOURCE;
956     switch (value) {
957         case static_cast<int32_t>(ResourceType::IMAGE_RESOURCE):
958         case static_cast<int32_t>(ResourceType::VIDEO_RESOURCE):
959         case static_cast<int32_t>(ResourceType::PHOTO_PROXY):
960             result = static_cast<ResourceType>(value);
961             break;
962         default:
963             break;
964     }
965     return result;
966 }
967 
CheckMovingPhotoVideo(void * dataBuffer,size_t size)968 static bool CheckMovingPhotoVideo(void* dataBuffer, size_t size)
969 {
970     auto dataSource = std::make_shared<MediaDataSource>(dataBuffer, static_cast<int64_t>(size));
971     auto avMetadataHelper = AVMetadataHelperFactory::CreateAVMetadataHelper();
972     if (avMetadataHelper == nullptr) {
973         LOGE("Failed to create AVMetadataHelper, ignore checking duration of moving photo video");
974         return true;
975     }
976 
977     int32_t err = avMetadataHelper->SetSource(dataSource);
978     if (err != E_OK) {
979         LOGE("SetSource failed for dataSource, err = %{public}d", err);
980         return false;
981     }
982 
983     std::unordered_map<int32_t, std::string> resultMap = avMetadataHelper->ResolveMetadata();
984     if (resultMap.find(AV_KEY_DURATION) == resultMap.end()) {
985         LOGE("AV_KEY_DURATION does not exist");
986         return false;
987     }
988 
989     std::string durationStr = resultMap.at(AV_KEY_DURATION);
990     int32_t duration = std::atoi(durationStr.c_str());
991     if (!MediaFileUtils::CheckMovingPhotoVideoDuration(duration)) {
992         LOGE("Failed to check duration of moving photo video: %{public}d ms", duration);
993         return false;
994     }
995     return true;
996 }
997 
AddMovingPhotoVideoResource(std::string fileUri)998 int32_t MediaAssetChangeRequestImpl::AddMovingPhotoVideoResource(std::string fileUri)
999 {
1000     std::string realPath;
1001     if (!ParseFileUri(fileUri, MediaType::MEDIA_TYPE_VIDEO, realPath)) {
1002         return OHOS_INVALID_PARAM_CODE;
1003     }
1004     if (!MediaFileUtils::CheckMovingPhotoVideo(realPath)) {
1005         LOGE("Failed to check video resource of moving photo");
1006         return OHOS_INVALID_PARAM_CODE;
1007     }
1008     movingPhotoVideoRealPath_ = realPath;
1009     movingPhotoVideoResourceMode_ = AddResourceMode::FILE_URI;
1010     RecordChangeOperation(AssetChangeOperation::ADD_RESOURCE);
1011     addResourceTypes_.push_back(ResourceType::VIDEO_RESOURCE);
1012     return 0;
1013 }
1014 
AddMovingPhotoVideoResource(uint8_t * dataBuffer,size_t dataBufferSize)1015 int32_t MediaAssetChangeRequestImpl::AddMovingPhotoVideoResource(uint8_t* dataBuffer, size_t dataBufferSize)
1016 {
1017     movingPhotoVideoDataBuffer_ = dataBuffer;
1018     movingPhotoVideoBufferSize_ = dataBufferSize;
1019     if (!CheckMovingPhotoVideo(movingPhotoVideoDataBuffer_, movingPhotoVideoBufferSize_)) {
1020         LOGE("Failed to check video resource of moving photo");
1021         return OHOS_INVALID_PARAM_CODE;
1022     }
1023     movingPhotoVideoResourceMode_ = AddResourceMode::DATA_BUFFER;
1024     RecordChangeOperation(AssetChangeOperation::ADD_RESOURCE);
1025     addResourceTypes_.push_back(ResourceType::VIDEO_RESOURCE);
1026     return 0;
1027 }
1028 
CJAddResource(int32_t resourceType,std::string fileUri)1029 int32_t MediaAssetChangeRequestImpl::CJAddResource(int32_t resourceType, std::string fileUri)
1030 {
1031     if (fileAsset_ == nullptr) {
1032         return JS_INNER_FAIL;
1033     }
1034     if (CheckWriteOperation(this, GetResourceType(resourceType)) != E_OK) {
1035         return JS_E_OPERATION_NOT_SUPPORT;
1036     }
1037     if (IsMovingPhoto() && resourceType == static_cast<int32_t>(ResourceType::VIDEO_RESOURCE)) {
1038         return AddMovingPhotoVideoResource(fileUri);
1039     }
1040     if (!(resourceType == static_cast<int32_t>(fileAsset_->GetMediaType()) ||
1041             resourceType == static_cast<int32_t>(ResourceType::PHOTO_PROXY))) {
1042         LOGE("Failed to check resourceType");
1043         return OHOS_INVALID_PARAM_CODE;
1044     }
1045     std::string realPath;
1046     if (!ParseFileUri(fileUri, fileAsset_->GetMediaType(), realPath)) {
1047         return OHOS_INVALID_PARAM_CODE;
1048     }
1049     realPath_ = realPath;
1050     addResourceMode_ = AddResourceMode::FILE_URI;
1051     RecordChangeOperation(AssetChangeOperation::ADD_RESOURCE);
1052     addResourceTypes_.push_back(GetResourceType(resourceType));
1053     return 0;
1054 }
1055 
CJAddResource(int32_t resourceType,uint8_t * dataBuffer,size_t dataBufferSize)1056 int32_t MediaAssetChangeRequestImpl::CJAddResource(int32_t resourceType, uint8_t* dataBuffer, size_t dataBufferSize)
1057 {
1058     if (dataBufferSize <= 0) {
1059         LOGE("Failed to check size of data buffer");
1060         return OHOS_INVALID_PARAM_CODE;
1061     }
1062     if (fileAsset_ == nullptr) {
1063         return JS_INNER_FAIL;
1064     }
1065     if (CheckWriteOperation(this, GetResourceType(resourceType)) != E_OK) {
1066         return JS_E_OPERATION_NOT_SUPPORT;
1067     }
1068     if (IsMovingPhoto() && resourceType == static_cast<int32_t>(ResourceType::VIDEO_RESOURCE)) {
1069         return AddMovingPhotoVideoResource(dataBuffer, dataBufferSize);
1070     }
1071     if (!(resourceType == static_cast<int32_t>(fileAsset_->GetMediaType()) ||
1072             resourceType == static_cast<int32_t>(ResourceType::PHOTO_PROXY))) {
1073         LOGE("Failed to check resourceType");
1074         return OHOS_INVALID_PARAM_CODE;
1075     }
1076     dataBuffer_ = dataBuffer;
1077     dataBufferSize_ = dataBufferSize;
1078     addResourceMode_ = AddResourceMode::DATA_BUFFER;
1079     RecordChangeOperation(AssetChangeOperation::ADD_RESOURCE);
1080     addResourceTypes_.push_back(GetResourceType(resourceType));
1081     return 0;
1082 }
1083 
CJSaveCameraPhoto()1084 int32_t MediaAssetChangeRequestImpl::CJSaveCameraPhoto()
1085 {
1086     if (fileAsset_ == nullptr) {
1087         return JS_INNER_FAIL;
1088     }
1089     if (Contains(AssetChangeOperation::SET_EDIT_DATA) && !Contains(AssetChangeOperation::ADD_FILTERS)) {
1090         RecordChangeOperation(AssetChangeOperation::ADD_FILTERS);
1091     }
1092     RecordChangeOperation(AssetChangeOperation::SAVE_CAMERA_PHOTO);
1093     return 0;
1094 }
1095 
CJDiscardCameraPhoto()1096 int32_t MediaAssetChangeRequestImpl::CJDiscardCameraPhoto()
1097 {
1098     if (fileAsset_ == nullptr) {
1099         return JS_INNER_FAIL;
1100     }
1101     RecordChangeOperation(AssetChangeOperation::DISCARD_CAMERA_PHOTO);
1102     return 0;
1103 }
1104 
CJSetOrientation(int32_t orientation)1105 int32_t MediaAssetChangeRequestImpl::CJSetOrientation(int32_t orientation)
1106 {
1107     if (fileAsset_ == nullptr) {
1108         return OHOS_INVALID_PARAM_CODE;
1109     }
1110     if (std::find(ORIENTATION_ARRAY.begin(), ORIENTATION_ARRAY.end(), orientation) == ORIENTATION_ARRAY.end()) {
1111         LOGE("orientationValue value is invalid.");
1112         return OHOS_INVALID_PARAM_CODE;
1113     }
1114     fileAsset_->SetOrientation(orientation);
1115     RecordChangeOperation(AssetChangeOperation::SET_ORIENTATION);
1116     return 0;
1117 }
1118 
IsCreation(MediaAssetChangeRequestImpl * changeRequest)1119 static bool IsCreation(MediaAssetChangeRequestImpl* changeRequest)
1120 {
1121     auto assetChangeOperations = changeRequest->GetAssetChangeOperations();
1122     bool isCreateFromScratch = std::find(assetChangeOperations.begin(), assetChangeOperations.end(),
1123         AssetChangeOperation::CREATE_FROM_SCRATCH) != assetChangeOperations.end();
1124     bool isCreateFromUri = std::find(assetChangeOperations.begin(), assetChangeOperations.end(),
1125         AssetChangeOperation::CREATE_FROM_URI) != assetChangeOperations.end();
1126     return isCreateFromScratch || isCreateFromUri;
1127 }
1128 
IsSetEffectMode(MediaAssetChangeRequestImpl * changeRequest)1129 static bool IsSetEffectMode(MediaAssetChangeRequestImpl* changeRequest)
1130 {
1131     auto assetChangeOperations = changeRequest->GetAssetChangeOperations();
1132     return std::find(assetChangeOperations.begin(), assetChangeOperations.end(),
1133         AssetChangeOperation::SET_MOVING_PHOTO_EFFECT_MODE) != assetChangeOperations.end();
1134 }
1135 
WriteBySecurityComponent(MediaAssetChangeRequestImpl * changeRequest)1136 static bool WriteBySecurityComponent(MediaAssetChangeRequestImpl* changeRequest)
1137 {
1138     bool isCreation = IsCreation(changeRequest);
1139     int32_t ret = E_FAIL;
1140     auto assetChangeOperations = changeRequest->GetAssetChangeOperations();
1141     bool isCreateFromUri = std::find(assetChangeOperations.begin(), assetChangeOperations.end(),
1142         AssetChangeOperation::CREATE_FROM_URI) != assetChangeOperations.end();
1143     if (isCreateFromUri) {
1144         ret = changeRequest->CopyToMediaLibrary(isCreation, AddResourceMode::FILE_URI);
1145     } else {
1146         ret = changeRequest->CopyToMediaLibrary(isCreation, changeRequest->GetAddResourceMode());
1147     }
1148 
1149     if (ret < 0) {
1150         LOGE("Failed to write by security component, ret: %{public}d", ret);
1151         return false;
1152     }
1153     return true;
1154 }
1155 
SendToCacheFile(MediaAssetChangeRequestImpl * changeRequest,const UniqueFd & destFd,bool isMovingPhotoVideo=false)1156 static bool SendToCacheFile(
1157     MediaAssetChangeRequestImpl* changeRequest, const UniqueFd& destFd, bool isMovingPhotoVideo = false)
1158 {
1159     std::string realPath =
1160         isMovingPhotoVideo ? changeRequest->GetMovingPhotoVideoPath() : changeRequest->GetFileRealPath();
1161 
1162     std::string absFilePath;
1163     if (!PathToRealPath(realPath, absFilePath)) {
1164         LOGE("Not real path %{private}s, errno=%{public}d", realPath.c_str(), errno);
1165         return false;
1166     }
1167 
1168     UniqueFd srcFd(open(absFilePath.c_str(), O_RDONLY));
1169     if (srcFd.Get() < 0) {
1170         LOGE("Failed to open file, errno=%{public}d", errno);
1171         return false;
1172     }
1173 
1174     int32_t err = SendFile(srcFd, destFd);
1175     if (err != E_OK) {
1176         LOGE("Failed to send file from %{public}d to %{public}d", srcFd.Get(), destFd.Get());
1177         return false;
1178     }
1179     return true;
1180 }
1181 
SubmitCache(bool isCreation,bool isSetEffectMode)1182 int32_t MediaAssetChangeRequestImpl::SubmitCache(bool isCreation, bool isSetEffectMode)
1183 {
1184     if (fileAsset_ == nullptr) {
1185         return E_FAIL;
1186     }
1187     if (cacheFileName_.empty() && cacheMovingPhotoVideoName_.empty()) {
1188         LOGE("Failed to check cache file");
1189         return E_FAIL;
1190     }
1191     std::string uri = PAH_SUBMIT_CACHE;
1192     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
1193     Uri submitCacheUri(uri);
1194     std::string assetUri;
1195     int32_t ret;
1196     if (isCreation) {
1197         bool isValid = false;
1198         std::string displayName = creationValuesBucket_.Get(MEDIA_DATA_DB_NAME, isValid);
1199         if (!isValid || MediaFileUtils::CheckDisplayName(displayName) != E_OK) {
1200             LOGE("Failed to check displayName");
1201             return E_FAIL;
1202         }
1203         creationValuesBucket_.Put(CACHE_FILE_NAME, cacheFileName_);
1204         if (IsMovingPhoto()) {
1205             creationValuesBucket_.Put(CACHE_MOVING_PHOTO_VIDEO_NAME, cacheMovingPhotoVideoName_);
1206         }
1207         ret = UserFileClient::InsertExt(submitCacheUri, creationValuesBucket_, assetUri);
1208     } else {
1209         DataShare::DataShareValuesBucket valuesBucket;
1210         valuesBucket.Put(PhotoColumn::MEDIA_ID, fileAsset_->GetId());
1211         valuesBucket.Put(CACHE_FILE_NAME, cacheFileName_);
1212         ret = PutMediaAssetEditData(valuesBucket);
1213         if (ret != E_OK) {
1214             LOGE("Failed to put editData");
1215             return E_FAIL;
1216         }
1217         if (IsMovingPhoto()) {
1218             valuesBucket.Put(CACHE_MOVING_PHOTO_VIDEO_NAME, cacheMovingPhotoVideoName_);
1219         }
1220         if (isSetEffectMode) {
1221             valuesBucket.Put(PhotoColumn::MOVING_PHOTO_EFFECT_MODE, fileAsset_->GetMovingPhotoEffectMode());
1222             valuesBucket.Put(CACHE_MOVING_PHOTO_VIDEO_NAME, cacheMovingPhotoVideoName_);
1223         }
1224         ret = UserFileClient::Insert(submitCacheUri, valuesBucket);
1225     }
1226     if (ret > 0 && isCreation) {
1227         SetNewFileAsset(ret, assetUri);
1228     }
1229     cacheFileName_.clear();
1230     cacheMovingPhotoVideoName_.clear();
1231     return ret;
1232 }
1233 
SubmitCacheExecute(MediaAssetChangeRequestImpl * changeRequest)1234 static bool SubmitCacheExecute(MediaAssetChangeRequestImpl* changeRequest)
1235 {
1236     bool isCreation = IsCreation(changeRequest);
1237     bool isSetEffectMode = IsSetEffectMode(changeRequest);
1238     int32_t ret = changeRequest->SubmitCache(isCreation, isSetEffectMode);
1239     if (ret < 0) {
1240         LOGE("Failed to write cache, ret: %{public}d", ret);
1241         return false;
1242     }
1243     return true;
1244 }
1245 
CreateFromFileUriExecute(MediaAssetChangeRequestImpl * changeRequest)1246 static bool CreateFromFileUriExecute(MediaAssetChangeRequestImpl* changeRequest)
1247 {
1248     if (!HasWritePermission()) {
1249         return WriteBySecurityComponent(changeRequest);
1250     }
1251 
1252     int32_t cacheFd = OpenWriteCacheHandler(changeRequest);
1253     if (cacheFd < 0) {
1254         LOGE("Failed to open write cache handler, err: %{public}d", cacheFd);
1255         return false;
1256     }
1257 
1258     UniqueFd uniqueFd(cacheFd);
1259     if (!SendToCacheFile(changeRequest, uniqueFd)) {
1260         LOGE("Faild to write cache file");
1261         return false;
1262     }
1263     return SubmitCacheExecute(changeRequest);
1264 }
1265 
HasAddResource(std::vector<ResourceType> addResourceTypes,ResourceType resourceType)1266 static bool HasAddResource(std::vector<ResourceType> addResourceTypes, ResourceType resourceType)
1267 {
1268     return std::find(addResourceTypes.begin(), addResourceTypes.end(), resourceType) != addResourceTypes.end();
1269 }
1270 
WriteCacheByArrayBuffer(MediaAssetChangeRequestImpl * changeRequest,const UniqueFd & destFd,bool isMovingPhotoVideo=false)1271 static bool WriteCacheByArrayBuffer(
1272     MediaAssetChangeRequestImpl* changeRequest, const UniqueFd& destFd, bool isMovingPhotoVideo = false)
1273 {
1274     size_t offset = 0;
1275     size_t length = isMovingPhotoVideo ? changeRequest->GetMovingPhotoVideoSize() : changeRequest->GetDataBufferSize();
1276     void* dataBuffer = isMovingPhotoVideo ? changeRequest->GetMovingPhotoVideoBuffer() : changeRequest->GetDataBuffer();
1277     while (offset < length) {
1278         ssize_t written = write(destFd.Get(), (char*)dataBuffer + offset, length - offset);
1279         if (written < 0) {
1280             LOGE("Failed to write data buffer to cache file, return %{public}d", static_cast<int>(written));
1281             return false;
1282         }
1283         offset += static_cast<size_t>(written);
1284     }
1285     return true;
1286 }
1287 
SavePhotoProxyImage(const UniqueFd & destFd,sptr<PhotoProxy> photoProxyPtr)1288 static int SavePhotoProxyImage(const UniqueFd& destFd, sptr<PhotoProxy> photoProxyPtr)
1289 {
1290     void* imageAddr = photoProxyPtr->GetFileDataAddr();
1291     size_t imageSize = photoProxyPtr->GetFileSize();
1292     if (imageAddr == nullptr || imageSize == 0) {
1293         LOGE("imageAddr is nullptr or imageSize(%{public}zu)==0", imageSize);
1294         return E_ERR;
1295     }
1296 
1297     NAPI_INFO_LOG("start pack PixelMap");
1298     Media::InitializationOptions opts;
1299     opts.pixelFormat = Media::PixelFormat::RGBA_8888;
1300     opts.size = { .width = photoProxyPtr->GetWidth(), .height = photoProxyPtr->GetHeight() };
1301     auto pixelMap = Media::PixelMap::Create(opts);
1302     if (pixelMap == nullptr) {
1303         LOGE("Create pixelMap failed.");
1304         return E_ERR;
1305     }
1306     pixelMap->SetPixelsAddr(imageAddr, nullptr, imageSize, Media::AllocatorType::SHARE_MEM_ALLOC, nullptr);
1307     auto pixelSize = static_cast<uint32_t>(pixelMap->GetByteCount());
1308 
1309     // encode rgba to jpeg
1310     auto buffer = new (std::nothrow) uint8_t[pixelSize];
1311     int64_t packedSize = 0L;
1312     Media::ImagePacker imagePacker;
1313     Media::PackOption packOption;
1314     packOption.format = "image/jpeg";
1315     imagePacker.StartPacking(buffer, pixelSize, packOption);
1316     imagePacker.AddImage(*pixelMap);
1317     imagePacker.FinalizePacking(packedSize);
1318     if (buffer == nullptr) {
1319         LOGE("packet pixelMap failed");
1320         return E_ERR;
1321     }
1322     NAPI_INFO_LOG("pack pixelMap success, packedSize: %{public}" PRId64, packedSize);
1323 
1324     int ret = write(destFd, buffer, packedSize);
1325     if (ret < 0) {
1326         LOGE("Failed to write photo proxy to cache file, return %{public}d", ret);
1327         delete[] buffer;
1328         return ret;
1329     }
1330     delete[] buffer;
1331     return ret;
1332 }
1333 
AddPhotoProxyResourceExecute(MediaAssetChangeRequestImpl * changeRequest,const UniqueFd & destFd)1334 static bool AddPhotoProxyResourceExecute(MediaAssetChangeRequestImpl* changeRequest, const UniqueFd& destFd)
1335 {
1336     std::string uri = PAH_ADD_IMAGE;
1337     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
1338     Uri updateAssetUri(uri);
1339 
1340     auto fileAsset = changeRequest->GetFileAssetInstance();
1341     DataShare::DataSharePredicates predicates;
1342     predicates.SetWhereClause(PhotoColumn::MEDIA_ID + " = ? ");
1343     predicates.SetWhereArgs({ std::to_string(fileAsset->GetId()) });
1344 
1345     DataShare::DataShareValuesBucket valuesBucket;
1346     valuesBucket.Put(PhotoColumn::PHOTO_ID, changeRequest->GetPhotoProxyObj()->GetPhotoId());
1347     NAPI_INFO_LOG("photoId: %{public}s", changeRequest->GetPhotoProxyObj()->GetPhotoId().c_str());
1348     valuesBucket.Put(PhotoColumn::PHOTO_DEFERRED_PROC_TYPE,
1349         static_cast<int32_t>(changeRequest->GetPhotoProxyObj()->GetDeferredProcType()));
1350     valuesBucket.Put(MediaColumn::MEDIA_ID, fileAsset->GetId());
1351     int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
1352     if (changedRows < 0) {
1353         LOGE("Failed to set, err: %{public}d", changedRows);
1354         return false;
1355     }
1356 
1357     int err = SavePhotoProxyImage(destFd, changeRequest->GetPhotoProxyObj());
1358     changeRequest->ReleasePhotoProxyObj();
1359     if (err < 0) {
1360         LOGE("Failed to saveImage , err: %{public}d", err);
1361         return false;
1362     }
1363     return true;
1364 }
1365 
AddResourceByMode(MediaAssetChangeRequestImpl * changeRequest,const UniqueFd & uniqueFd,AddResourceMode mode,bool isMovingPhotoVideo=false)1366 static bool AddResourceByMode(MediaAssetChangeRequestImpl* changeRequest, const UniqueFd& uniqueFd,
1367     AddResourceMode mode, bool isMovingPhotoVideo = false)
1368 {
1369     bool isWriteSuccess = false;
1370     if (mode == AddResourceMode::DATA_BUFFER) {
1371         isWriteSuccess = WriteCacheByArrayBuffer(changeRequest, uniqueFd, isMovingPhotoVideo);
1372     } else if (mode == AddResourceMode::FILE_URI) {
1373         isWriteSuccess = SendToCacheFile(changeRequest, uniqueFd, isMovingPhotoVideo);
1374     } else if (mode == AddResourceMode::PHOTO_PROXY) {
1375         isWriteSuccess = AddPhotoProxyResourceExecute(changeRequest, uniqueFd);
1376     } else {
1377         LOGE("Unsupported addResource mode");
1378     }
1379     return isWriteSuccess;
1380 }
1381 
AddMovingPhotoVideoExecute(MediaAssetChangeRequestImpl * changeRequest)1382 static bool AddMovingPhotoVideoExecute(MediaAssetChangeRequestImpl* changeRequest)
1383 {
1384     int32_t cacheVideoFd = OpenWriteCacheHandler(changeRequest, true);
1385     if (cacheVideoFd < 0) {
1386         LOGE("Failed to open cache moving photo video, err: %{public}d", cacheVideoFd);
1387         return false;
1388     }
1389 
1390     UniqueFd uniqueFd(cacheVideoFd);
1391     AddResourceMode mode = changeRequest->GetMovingPhotoVideoMode();
1392     if (!AddResourceByMode(changeRequest, uniqueFd, mode, true)) {
1393         LOGE("Faild to write cache file");
1394         return false;
1395     }
1396     return true;
1397 }
1398 
AddResourceExecute(MediaAssetChangeRequestImpl * changeRequest)1399 static bool AddResourceExecute(MediaAssetChangeRequestImpl* changeRequest)
1400 {
1401     if (!HasWritePermission()) {
1402         return WriteBySecurityComponent(changeRequest);
1403     }
1404 
1405     if (changeRequest->IsMovingPhoto() &&
1406         HasAddResource(changeRequest->GetAddResourceTypes(), ResourceType::VIDEO_RESOURCE) &&
1407         !AddMovingPhotoVideoExecute(changeRequest)) {
1408         LOGE("Faild to write cache file for video of moving photo");
1409         return false;
1410     }
1411 
1412     // image resource is not mandatory when setting effect mode of moving photo
1413     if (changeRequest->IsMovingPhoto() &&
1414         !HasAddResource(changeRequest->GetAddResourceTypes(), ResourceType::IMAGE_RESOURCE)) {
1415         return SubmitCacheExecute(changeRequest);
1416     }
1417 
1418     int32_t cacheFd = OpenWriteCacheHandler(changeRequest);
1419     if (cacheFd < 0) {
1420         LOGE("Failed to open write cache handler, err: %{public}d", cacheFd);
1421         return false;
1422     }
1423 
1424     UniqueFd uniqueFd(cacheFd);
1425     AddResourceMode mode = changeRequest->GetAddResourceMode();
1426     if (!AddResourceByMode(changeRequest, uniqueFd, mode)) {
1427         LOGE("Faild to write cache file");
1428         return false;
1429     }
1430     return SubmitCacheExecute(changeRequest);
1431 }
1432 
UpdateAssetProperty(MediaAssetChangeRequestImpl * changeRequest,std::string uri,DataShare::DataSharePredicates & predicates,DataShare::DataShareValuesBucket & valuesBucket)1433 static bool UpdateAssetProperty(MediaAssetChangeRequestImpl* changeRequest, std::string uri,
1434     DataShare::DataSharePredicates& predicates, DataShare::DataShareValuesBucket& valuesBucket)
1435 {
1436     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
1437     Uri updateAssetUri(uri);
1438     int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
1439     if (changedRows < 0) {
1440         LOGE("Failed to update property of asset, err: %{public}d", changedRows);
1441         return false;
1442     }
1443     return true;
1444 }
1445 
SetTitleExecute(MediaAssetChangeRequestImpl * changeRequest)1446 static bool SetTitleExecute(MediaAssetChangeRequestImpl* changeRequest)
1447 {
1448     // In the scenario of creation, the new title will be applied when the asset is created.
1449     AssetChangeOperation firstOperation = changeRequest->GetAssetChangeOperations().front();
1450     if (firstOperation == AssetChangeOperation::CREATE_FROM_SCRATCH ||
1451         firstOperation == AssetChangeOperation::CREATE_FROM_URI) {
1452         return true;
1453     }
1454 
1455     DataShare::DataSharePredicates predicates;
1456     DataShare::DataShareValuesBucket valuesBucket;
1457     auto fileAsset = changeRequest->GetFileAssetInstance();
1458     predicates.EqualTo(PhotoColumn::MEDIA_ID, std::to_string(fileAsset->GetId()));
1459     valuesBucket.Put(PhotoColumn::MEDIA_TITLE, fileAsset->GetTitle());
1460     return UpdateAssetProperty(changeRequest, PAH_UPDATE_PHOTO, predicates, valuesBucket);
1461 }
1462 
DiscardHighQualityPhoto(MediaAssetChangeRequestImpl * changeRequest)1463 static void DiscardHighQualityPhoto(MediaAssetChangeRequestImpl* changeRequest)
1464 {
1465     std::string uriStr = PAH_REMOVE_MSC_TASK;
1466     MediaLibraryNapiUtils::UriAppendKeyValue(uriStr, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
1467     Uri uri(uriStr);
1468     DataShare::DataSharePredicates predicates;
1469     int errCode = 0;
1470     auto fileAsset = changeRequest->GetFileAssetInstance();
1471     std::vector<std::string> columns { std::to_string(fileAsset->GetId()) };
1472     UserFileClient::Query(uri, predicates, columns, errCode);
1473 }
1474 
SaveCameraPhotoExecute(MediaAssetChangeRequestImpl * changeRequest)1475 static bool SaveCameraPhotoExecute(MediaAssetChangeRequestImpl* changeRequest)
1476 {
1477     auto changeOpreations = changeRequest->GetAssetChangeOperations();
1478     bool containsAddResource = std::find(changeOpreations.begin(), changeOpreations.end(),
1479         AssetChangeOperation::ADD_RESOURCE) != changeOpreations.end();
1480     if (containsAddResource && !MediaLibraryNapiUtils::IsSystemApp()) {
1481         // remove high quality photo
1482         LOGI("discard high quality photo because add resource by third app");
1483         DiscardHighQualityPhoto(changeRequest);
1484     }
1485 
1486     // The watermark will trigger the scan. If the watermark is turned on, there is no need to trigger the scan again.
1487     bool needScan = std::find(changeOpreations.begin(), changeOpreations.end(),
1488         AssetChangeOperation::ADD_FILTERS) == changeOpreations.end();
1489 
1490     auto fileAsset = changeRequest->GetFileAssetInstance();
1491     if (fileAsset == nullptr) {
1492         LOGE("fileAsset is nullptr");
1493         return false;
1494     }
1495     std::string uriStr = PAH_SAVE_CAMERA_PHOTO;
1496     MediaLibraryNapiUtils::UriAppendKeyValue(uriStr, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
1497     MediaLibraryNapiUtils::UriAppendKeyValue(uriStr, MEDIA_OPERN_KEYWORD, std::to_string(needScan));
1498     MediaLibraryNapiUtils::UriAppendKeyValue(uriStr, PhotoColumn::MEDIA_FILE_PATH, fileAsset->GetUri());
1499     MediaLibraryNapiUtils::UriAppendKeyValue(uriStr, PhotoColumn::MEDIA_ID, std::to_string(fileAsset->GetId()));
1500     MediaLibraryNapiUtils::UriAppendKeyValue(
1501         uriStr, PhotoColumn::PHOTO_SUBTYPE, std::to_string(fileAsset->GetPhotoSubType()));
1502     MediaLibraryNapiUtils::UriAppendKeyValue(
1503         uriStr, IMAGE_FILE_TYPE, std::to_string(changeRequest->GetImageFileType()));
1504     Uri uri(uriStr);
1505     DataShare::DataShareValuesBucket valuesBucket;
1506     valuesBucket.Put(PhotoColumn::PHOTO_IS_TEMP, false);
1507     DataShare::DataSharePredicates predicates;
1508     auto ret = UserFileClient::Update(uri, predicates, valuesBucket);
1509     if (ret < 0) {
1510         LOGE("save camera photo fail");
1511     }
1512     return true;
1513 }
1514 
AddFiltersExecute(MediaAssetChangeRequestImpl * changeRequest)1515 static bool AddFiltersExecute(MediaAssetChangeRequestImpl* changeRequest)
1516 {
1517     auto fileAsset = changeRequest->GetFileAssetInstance();
1518     if (fileAsset == nullptr) {
1519         LOGE("Failed to check fileAsset");
1520         return false;
1521     }
1522     std::string uri = PAH_ADD_FILTERS;
1523     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
1524     Uri addFiltersUri(uri);
1525 
1526     DataShare::DataShareValuesBucket valuesBucket;
1527     valuesBucket.Put(PhotoColumn::MEDIA_ID, fileAsset->GetId());
1528     int ret = changeRequest->PutMediaAssetEditData(valuesBucket);
1529     if (ret != E_OK) {
1530         LOGE("Failed to put editData");
1531         return false;
1532     }
1533     ret = UserFileClient::Insert(addFiltersUri, valuesBucket);
1534     if (ret < 0) {
1535         LOGE("Failed to add filters, ret: %{public}d", ret);
1536         return false;
1537     }
1538     return true;
1539 }
1540 
DiscardCameraPhotoExecute(MediaAssetChangeRequestImpl * changeRequest)1541 static bool DiscardCameraPhotoExecute(MediaAssetChangeRequestImpl* changeRequest)
1542 {
1543     DataShare::DataSharePredicates predicates;
1544     DataShare::DataShareValuesBucket valuesBucket;
1545     valuesBucket.Put(PhotoColumn::PHOTO_IS_TEMP, true);
1546     auto fileAsset = changeRequest->GetFileAssetInstance();
1547     predicates.EqualTo(PhotoColumn::MEDIA_ID, std::to_string(fileAsset->GetId()));
1548     predicates.EqualTo(PhotoColumn::PHOTO_IS_TEMP, "1"); // only temp camera photo can be discarded
1549 
1550     std::string uri = PAH_DISCARD_CAMERA_PHOTO;
1551     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
1552     Uri updateAssetUri(uri);
1553     int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
1554     if (changedRows < 0) {
1555         LOGE("Failed to update property of asset, err: %{public}d", changedRows);
1556         return false;
1557     }
1558     return true;
1559 }
1560 
SetOrientationExecute(MediaAssetChangeRequestImpl * changeRequest)1561 static bool SetOrientationExecute(MediaAssetChangeRequestImpl* changeRequest)
1562 {
1563     DataShare::DataSharePredicates predicates;
1564     DataShare::DataShareValuesBucket valuesBucket;
1565     auto fileAsset = changeRequest->GetFileAssetInstance();
1566     if (fileAsset == nullptr) {
1567         LOGE("fileAsset is null");
1568         return false;
1569     }
1570     predicates.EqualTo(PhotoColumn::MEDIA_ID, std::to_string(fileAsset->GetId()));
1571     valuesBucket.Put(PhotoColumn::PHOTO_ORIENTATION, fileAsset->GetOrientation());
1572     return UpdateAssetProperty(changeRequest, PAH_UPDATE_PHOTO, predicates, valuesBucket);
1573 }
1574 
1575 static const std::unordered_map<AssetChangeOperation, bool (*)(MediaAssetChangeRequestImpl*)> EXECUTE_MAP = {
1576     { AssetChangeOperation::CREATE_FROM_URI, CreateFromFileUriExecute },
1577     { AssetChangeOperation::GET_WRITE_CACHE_HANDLER, SubmitCacheExecute },
1578     { AssetChangeOperation::ADD_RESOURCE, AddResourceExecute },
1579     { AssetChangeOperation::SET_TITLE, SetTitleExecute },
1580     { AssetChangeOperation::SET_ORIENTATION, SetOrientationExecute },
1581     { AssetChangeOperation::SAVE_CAMERA_PHOTO, SaveCameraPhotoExecute },
1582     { AssetChangeOperation::ADD_FILTERS, AddFiltersExecute },
1583     { AssetChangeOperation::DISCARD_CAMERA_PHOTO, DiscardCameraPhotoExecute },
1584 };
1585 
ApplyChanges()1586 int32_t MediaAssetChangeRequestImpl::ApplyChanges()
1587 {
1588     if (!CheckChangeOperations()) {
1589         LOGE("Failed to check asset change request operations");
1590         return OHOS_INVALID_PARAM_CODE;
1591     }
1592     std::unordered_set<AssetChangeOperation> appliedOperations;
1593     for (const auto& changeOperation : assetChangeOperations_) {
1594         // Keep the final result of each operation, and commit it only once.
1595         if (appliedOperations.find(changeOperation) != appliedOperations.end()) {
1596             continue;
1597         }
1598 
1599         bool valid = false;
1600         auto iter = EXECUTE_MAP.find(changeOperation);
1601         if (iter != EXECUTE_MAP.end()) {
1602             valid = iter->second(this);
1603         } else if (changeOperation == AssetChangeOperation::CREATE_FROM_SCRATCH ||
1604                    changeOperation == AssetChangeOperation::SET_EDIT_DATA) {
1605             // Perform CREATE_FROM_SCRATCH and SET_EDIT_DATA during GET_WRITE_CACHE_HANDLER or ADD_RESOURCE.
1606             valid = true;
1607         } else {
1608             LOGE("Invalid asset change operation: %{public}d", changeOperation);
1609             assetChangeOperations_.clear();
1610             addResourceTypes_.clear();
1611             return OHOS_INVALID_PARAM_CODE;
1612         }
1613 
1614         if (!valid) {
1615             LOGE("Failed to apply asset change request, operation: %{public}d", changeOperation);
1616             assetChangeOperations_.clear();
1617             addResourceTypes_.clear();
1618             return 0;
1619         }
1620         appliedOperations.insert(changeOperation);
1621     }
1622     assetChangeOperations_.clear();
1623     addResourceTypes_.clear();
1624     return 0;
1625 }
1626 } // namespace Media
1627 } // namespace OHOS