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 #define MLOG_TAG "PhotoFileOperation"
16
17 #include "photo_file_operation.h"
18
19 #include <sstream>
20
21 #include "media_log.h"
22 #include "medialibrary_errno.h"
23 #include "medialibrary_kvstore_utils.h"
24 #include "userfile_manager_types.h"
25 #include "media_file_utils.h"
26 #include "moving_photo_file_utils.h"
27 #include "media_column.h"
28 #include "result_set_utils.h"
29
30 namespace OHOS::Media {
31 // LCOV_EXCL_START
ToString(const PhotoAssetInfo & photoInfo)32 std::string PhotoFileOperation::ToString(const PhotoAssetInfo &photoInfo)
33 {
34 std::stringstream ss;
35 ss << "PhotoAssetInfo[displayName: " << photoInfo.displayName << ", filePath: " << photoInfo.filePath
36 << ", dateModified: " << photoInfo.dateModified << ", subtype: " << photoInfo.subtype
37 << ", videoFilePath: " << photoInfo.videoFilePath << ", editDataFolder: " << photoInfo.editDataFolder
38 << ", thumbnailFolder: " << photoInfo.thumbnailFolder << ", isMovingPhoto: " << photoInfo.isMovingPhoto << "]";
39 return ss.str();
40 }
41
42 /**
43 * @brief Copy Photo File, include photo file, video file and edit data folder.
44 */
CopyPhoto(const std::shared_ptr<NativeRdb::ResultSet> & resultSet,const std::string & targetPath)45 int32_t PhotoFileOperation::CopyPhoto(
46 const std::shared_ptr<NativeRdb::ResultSet> &resultSet, const std::string &targetPath)
47 {
48 bool cond = (resultSet == nullptr || targetPath.empty());
49 CHECK_AND_RETURN_RET_LOG(!cond, E_FAIL,
50 "Media_Operation: CopyPhoto failed, resultSet is null or targetPath is empty");
51
52 // Build the Original Photo Asset Info
53 PhotoFileOperation::PhotoAssetInfo sourcePhotoInfo;
54 sourcePhotoInfo.displayName = GetStringVal(MediaColumn::MEDIA_NAME, resultSet);
55 sourcePhotoInfo.filePath = GetStringVal(MediaColumn::MEDIA_FILE_PATH, resultSet);
56 sourcePhotoInfo.subtype = GetInt32Val(PhotoColumn::PHOTO_SUBTYPE, resultSet);
57 int32_t originalSubtype = GetInt32Val(PhotoColumn::PHOTO_ORIGINAL_SUBTYPE, resultSet);
58 int32_t effectMode = GetInt32Val(PhotoColumn::MOVING_PHOTO_EFFECT_MODE, resultSet);
59 sourcePhotoInfo.isMovingPhoto = MovingPhotoFileUtils::IsMovingPhoto(
60 sourcePhotoInfo.subtype, effectMode, originalSubtype);
61 sourcePhotoInfo.dateModified = GetInt64Val(MediaColumn::MEDIA_DATE_MODIFIED, resultSet);
62 sourcePhotoInfo.videoFilePath = this->FindVideoFilePath(sourcePhotoInfo);
63 sourcePhotoInfo.editDataFolder = this->FindEditDataFolder(sourcePhotoInfo);
64 // Build the Target Photo Asset Info
65 PhotoFileOperation::PhotoAssetInfo targetPhotoInfo;
66 targetPhotoInfo.displayName = sourcePhotoInfo.displayName;
67 targetPhotoInfo.filePath = targetPath;
68 targetPhotoInfo.subtype = sourcePhotoInfo.subtype;
69 targetPhotoInfo.dateModified = sourcePhotoInfo.dateModified;
70 // No need to copy video file if the Original Photo is not a moving photo.
71 if (!sourcePhotoInfo.videoFilePath.empty()) {
72 targetPhotoInfo.videoFilePath = this->GetVideoFilePath(targetPhotoInfo);
73 }
74 // No need to copy edit data folder if the Original Photo is not edited.
75 if (!sourcePhotoInfo.editDataFolder.empty()) {
76 targetPhotoInfo.editDataFolder = this->BuildEditDataFolder(targetPhotoInfo);
77 }
78 MEDIA_INFO_LOG("Media_Operation: sourcePhotoInfo: %{public}s, targetPhotoInfo: %{public}s",
79 this->ToString(sourcePhotoInfo).c_str(),
80 this->ToString(targetPhotoInfo).c_str());
81 return this->CopyPhoto(sourcePhotoInfo, targetPhotoInfo);
82 }
83
84 /**
85 * @brief Copy thumbnail, include folder and astc data.
86 */
CopyThumbnail(const std::shared_ptr<NativeRdb::ResultSet> & resultSet,const std::string & targetPath,int64_t & newAssetId)87 int32_t PhotoFileOperation::CopyThumbnail(
88 const std::shared_ptr<NativeRdb::ResultSet> &resultSet, const std::string &targetPath, int64_t &newAssetId)
89 {
90 bool cond = (resultSet == nullptr || targetPath.empty());
91 CHECK_AND_RETURN_RET_LOG(!cond, E_FAIL,
92 "Media_Operation: CopyPhoto failed, resultSet is null or targetPath is empty");
93
94 // Build the Original Photo Asset Info
95 PhotoFileOperation::PhotoAssetInfo sourcePhotoInfo;
96 sourcePhotoInfo.filePath = GetStringVal(MediaColumn::MEDIA_FILE_PATH, resultSet);
97 sourcePhotoInfo.thumbnailFolder = this->FindThumbnailFolder(sourcePhotoInfo);
98 if (sourcePhotoInfo.thumbnailFolder.empty()) {
99 MEDIA_INFO_LOG("Source thumbnail is empty, skip copy. thumbnailFolder:%{public}s",
100 sourcePhotoInfo.thumbnailFolder.c_str());
101 return E_FAIL;
102 }
103
104 // copy folder
105 PhotoFileOperation::PhotoAssetInfo targetPhotoInfo;
106 targetPhotoInfo.filePath = targetPath;
107 targetPhotoInfo.thumbnailFolder = this->BuildThumbnailFolder(targetPhotoInfo);
108 int32_t opRet = this->CopyPhotoRelatedThumbnail(sourcePhotoInfo, targetPhotoInfo);
109 CHECK_AND_RETURN_RET(opRet == E_OK, opRet);
110
111 std::string dateTaken = to_string(GetInt64Val(MediaColumn::MEDIA_DATE_TAKEN, resultSet));
112 std::string oldAssetId = to_string(GetInt64Val(MediaColumn::MEDIA_ID, resultSet));
113 return HandleThumbnailAstcData(dateTaken, oldAssetId, to_string(newAssetId));
114 }
115
HandleThumbnailAstcData(const std::string & dateTaken,const std::string & oldAssetId,const std::string & newAssetId)116 int32_t PhotoFileOperation::HandleThumbnailAstcData(const std::string &dateTaken, const std::string &oldAssetId,
117 const std::string &newAssetId)
118 {
119 // 取旧key拿value,然后在put新key和value(和旧的value一样)到kvstore中
120 string oldKey;
121 CHECK_AND_RETURN_RET_LOG(MediaFileUtils::GenerateKvStoreKey(oldAssetId, dateTaken, oldKey), E_ERR,
122 "GenerateKvStoreKey failed");
123
124 string newKey;
125 CHECK_AND_RETURN_RET_LOG(MediaFileUtils::GenerateKvStoreKey(newAssetId, dateTaken, newKey), E_ERR,
126 "GenerateKvStoreKey failed");
127
128 int32_t err = MediaLibraryKvStoreUtils::CopyAstcDataToKvStoreByType(KvStoreValueType::MONTH_ASTC, oldKey, newKey);
129 CHECK_AND_RETURN_RET_LOG(err == E_OK, err, "CopyAstcDataToKvStoreByType failed, err: %{public}d", err);
130
131 err = MediaLibraryKvStoreUtils::CopyAstcDataToKvStoreByType(KvStoreValueType::YEAR_ASTC, oldKey, newKey);
132 CHECK_AND_RETURN_RET_LOG(err == E_OK, err, "CopyAstcDataToKvStoreByType failed, err: %{public}d", err);
133 MEDIA_INFO_LOG("Success to copy thumbnail. oldKey:%{public}s, newKey:%{public}s", oldKey.c_str(), newKey.c_str());
134 return E_OK;
135 }
136
137 /**
138 * @brief Copy Photo File, include photo file, video file and edit data folder.
139 */
CopyPhoto(const PhotoFileOperation::PhotoAssetInfo & sourcePhotoInfo,const PhotoFileOperation::PhotoAssetInfo & targetPhotoInfo)140 int32_t PhotoFileOperation::CopyPhoto(const PhotoFileOperation::PhotoAssetInfo &sourcePhotoInfo,
141 const PhotoFileOperation::PhotoAssetInfo &targetPhotoInfo)
142 {
143 int32_t opRet = this->CopyPhotoFile(sourcePhotoInfo, targetPhotoInfo);
144 CHECK_AND_RETURN_RET(opRet == E_OK, opRet);
145
146 opRet = this->CopyPhotoRelatedVideoFile(sourcePhotoInfo, targetPhotoInfo);
147 CHECK_AND_RETURN_RET(opRet == E_OK, opRet);
148
149 return this->CopyPhotoRelatedExtraData(sourcePhotoInfo, targetPhotoInfo);
150 }
151
152 /**
153 * @brief Get the video file path of the photo, without any check.
154 * @return the video file path of the photo. Only replace the suffix of file extension, such as .jpg to .mp4.
155 * @example if filePath is /xxx/.../xxx/123456789.jpg, then return /xxx/.../xxx/123456789.mp4.
156 */
GetVideoFilePath(const PhotoFileOperation::PhotoAssetInfo & photoInfo)157 std::string PhotoFileOperation::GetVideoFilePath(const PhotoFileOperation::PhotoAssetInfo &photoInfo)
158 {
159 return MediaFileUtils::GetMovingPhotoVideoPath(photoInfo.filePath);
160 }
161
162 /**
163 * @brief Get the video file path of the photo, without any check.
164 * @return the video file path of the photo. Only replace the suffix of file extension, such as .jpg to .mp4.
165 * If the photo is not a moving photo, return an empty string.
166 * If the photo's file path is empty, return an empty string.
167 * If the photo is a moving photo, return the video file path of the photo.
168 */
FindVideoFilePath(const PhotoFileOperation::PhotoAssetInfo & photoInfo)169 std::string PhotoFileOperation::FindVideoFilePath(const PhotoFileOperation::PhotoAssetInfo &photoInfo)
170 {
171 if (!photoInfo.isMovingPhoto) {
172 return "";
173 }
174 // If file path is empty, return empty string. Trace log will be printed in CopyPhotoFile.
175 CHECK_AND_RETURN_RET(!photoInfo.filePath.empty(), "");
176
177 std::string videoFilePath = this->GetVideoFilePath(photoInfo);
178 if (!MediaFileUtils::IsFileExists(videoFilePath)) {
179 MEDIA_WARN_LOG("Media_Operation: videoFilePath not exists, videoFilePath: %{public}s, Object: %{public}s.",
180 videoFilePath.c_str(),
181 this->ToString(photoInfo).c_str());
182 return "";
183 }
184 return videoFilePath;
185 }
186
187 /**
188 * @brief Find the Relative Path of filePath.
189 * @return Relative Path.
190 * If prefix of filePath is "/storage/cloud/files", return the relative path of cloud prefix.
191 * If prefix of filePath is "/storage/media/local/files", return the relative path of local prefix.
192 * Otherwise, return empty string.
193 */
FindRelativePath(const std::string & filePath)194 std::string PhotoFileOperation::FindRelativePath(const std::string &filePath)
195 {
196 std::string prefix = "/storage/cloud/files";
197 size_t pos = filePath.find(prefix);
198 CHECK_AND_RETURN_RET(pos == std::string::npos, filePath.substr(pos + prefix.size()));
199
200 prefix = "/storage/media/local/files";
201 pos = filePath.find(prefix);
202 CHECK_AND_RETURN_RET(pos == std::string::npos, filePath.substr(pos + prefix.size()));
203 MEDIA_ERR_LOG("Media_Operation: Find RelativePath failed, filePath: %{public}s", filePath.c_str());
204 return "";
205 }
206
207 /**
208 * @brief Find the prefix of photo Data Folder.
209 * @return Return the prefix of photo Data Folder.
210 * There are two prefixes, one is local, the other is cloud.
211 * If the prefix of filePath is cloud, return "/storage/cloud/files/" + dataName.
212 * If the prefix of filePath is local, return "/storage/media/local/files/" + dataName;
213 * If the prefix of filePath is not found, return "".
214 */
FindPrefixDataFolder(const std::string & filePath,const std::string & dataName)215 std::string PhotoFileOperation::FindPrefixDataFolder(const std::string &filePath, const std::string &dataName)
216 {
217 std::string prefix = "/storage/cloud/files";
218 size_t pos = filePath.find(prefix);
219 if (pos != std::string::npos) {
220 return "/storage/cloud/files/" + dataName;
221 }
222 prefix = "/storage/media/local/files";
223 pos = filePath.find(prefix);
224 if (pos != std::string::npos) {
225 return "/storage/media/local/files/" + dataName;
226 }
227 MEDIA_WARN_LOG("Media_Operation: Get Prefix failed, filePath: %{public}s", filePath.c_str());
228 return "";
229 }
230
231 /**
232 * @brief Find the prefix of Edit Data Folder.
233 * @return Return the prefix of Edit Data Folder.
234 * There are two prefixes, one is local, the other is cloud.
235 * If the prefix of filePath is cloud, return "/storage/cloud/files/.editData".
236 * If the prefix of filePath is local, return "/storage/media/local/files/.editData";
237 * If the prefix of filePath is not found, return "".
238 */
FindPrefixOfEditDataFolder(const std::string & filePath)239 std::string PhotoFileOperation::FindPrefixOfEditDataFolder(const std::string &filePath)
240 {
241 return FindPrefixDataFolder(filePath, ".editData");
242 }
243
244 /**
245 * @brief Find the prefix of thumbs Data Folder.
246 * @return Return the prefix of thumbs Data Folder.
247 * There are two prefixes, one is local, the other is cloud.
248 * If the prefix of filePath is cloud, return "/storage/cloud/files/.thumbs".
249 * If the prefix of filePath is local, return "/storage/media/local/files/.thumbs";
250 * If the prefix of filePath is not found, return "".
251 */
FindPrefixOfThumbnailFolder(const std::string & filePath)252 std::string PhotoFileOperation::FindPrefixOfThumbnailFolder(const std::string &filePath)
253 {
254 return FindPrefixDataFolder(filePath, ".thumbs");
255 }
256
257 /**
258 * @brief Build the Edit Data Folder for the Photo file, without any check.
259 * @return Return the Edit Data Folder for the Photo file.
260 * If the filePath is cloud, return "/storage/cloud/files/.editData/" + the relativePath of Photo file.
261 * If the filePath is local, return "/storage/media/local/files/.editData/" + the relativePath of Photo file.
262 * If the filePath is not identified, return "".
263 */
BuildEditDataFolder(const PhotoFileOperation::PhotoAssetInfo & photoInfo)264 std::string PhotoFileOperation::BuildEditDataFolder(const PhotoFileOperation::PhotoAssetInfo &photoInfo)
265 {
266 std::string prefix = this->FindPrefixOfEditDataFolder(photoInfo.filePath);
267 std::string relativePath = this->FindRelativePath(photoInfo.filePath);
268 if (prefix.empty() || relativePath.empty()) {
269 return "";
270 }
271 return prefix + relativePath;
272 }
273
274 /**
275 * @brief Build the thumbs Data Folder for the Photo file, without any check.
276 * @return Return the thumbs Data Folder for the Photo file.
277 * If the filePath is cloud, return "/storage/cloud/files/.thumbs/" + the relativePath of Photo file.
278 * If the filePath is local, return "/storage/media/local/files/.thumbs/" + the relativePath of Photo file.
279 * If the filePath is not identified, return "".
280 */
BuildThumbnailFolder(const PhotoFileOperation::PhotoAssetInfo & photoInfo)281 std::string PhotoFileOperation::BuildThumbnailFolder(const PhotoFileOperation::PhotoAssetInfo &photoInfo)
282 {
283 std::string prefix = this->FindPrefixOfThumbnailFolder(photoInfo.filePath);
284 std::string relativePath = this->FindRelativePath(photoInfo.filePath);
285 if (prefix.empty() || relativePath.empty()) {
286 return "";
287 }
288 return prefix + relativePath;
289 }
290
291 /**
292 * @brief Find the thumbs Data Folder for the Photo file.
293 * @return Return the thumbs Data Folder path. If the thumbs Data Folder is invalid, return empty string.
294 * If the thumbs Data Folder is not exist, has 3 scenario:
295 * 1. The photo file is not thumbs. Normal scenario.
296 * 2. The photo file is not MOVING_PHOTO. Noraml scenario.
297 * 3. The photo file is thumbs or MOVING_PHOTO, but the thumbs Data Folder is not exist. Exceptional scenario.
298 */
FindThumbnailFolder(const PhotoFileOperation::PhotoAssetInfo & photoInfo)299 std::string PhotoFileOperation::FindThumbnailFolder(const PhotoFileOperation::PhotoAssetInfo &photoInfo)
300 {
301 std::string thumbnailFolderPath = this->BuildThumbnailFolder(photoInfo);
302 if (!thumbnailFolderPath.empty() && !MediaFileUtils::IsFileExists(thumbnailFolderPath)) {
303 MEDIA_INFO_LOG("Media_Operation: thumbnailFolder not exists, Object: %{public}s.",
304 this->ToString(photoInfo).c_str());
305 return "";
306 }
307 return thumbnailFolderPath;
308 }
309
310 /**
311 * @brief Find the Edit Data Folder for the Photo file.
312 * @return Return the Edit Data Folder path. If the Edit Data Folder is invalid, return empty string.
313 * If the Edit Data Folder is not exist, has 3 scenario:
314 * 1. The photo file is not edited. Normal scenario.
315 * 2. The photo file is not MOVING_PHOTO. Noraml scenario.
316 * 3. The photo file is edited or MOVING_PHOTO, but the Edit Data Folder is not exist. Exceptional scenario.
317 */
FindEditDataFolder(const PhotoFileOperation::PhotoAssetInfo & photoInfo)318 std::string PhotoFileOperation::FindEditDataFolder(const PhotoFileOperation::PhotoAssetInfo &photoInfo)
319 {
320 std::string editDataFolderPath = this->BuildEditDataFolder(photoInfo);
321 if (!editDataFolderPath.empty() && !MediaFileUtils::IsFileExists(editDataFolderPath)) {
322 MEDIA_INFO_LOG("Media_Operation: EditDataFolder not exists, It may not be edited photo or moving photo. "
323 "Object: %{public}s.",
324 this->ToString(photoInfo).c_str());
325 return "";
326 }
327 return editDataFolderPath;
328 }
329
330 /**
331 * @brief Copy Photo File, only include the photo file defined in the Photos table.
332 * @return E_OK if success,
333 * E_INVALID_PATH if the source file or target file is invalid,
334 * E_FILE_OPER_FAIL if the copy operation failed.
335 */
CopyPhotoFile(const PhotoFileOperation::PhotoAssetInfo & sourcePhotoInfo,const PhotoFileOperation::PhotoAssetInfo & targetPhotoInfo)336 int32_t PhotoFileOperation::CopyPhotoFile(const PhotoFileOperation::PhotoAssetInfo &sourcePhotoInfo,
337 const PhotoFileOperation::PhotoAssetInfo &targetPhotoInfo)
338 {
339 std::string srcPath = sourcePhotoInfo.filePath;
340 std::string targetPath = targetPhotoInfo.filePath;
341 int64_t dateModified = targetPhotoInfo.dateModified;
342 // If File Path is empty, return E_INVALID_PATH.
343 if (srcPath.empty() || targetPath.empty()) {
344 MEDIA_ERR_LOG("Media_Operation: CopyPhotoFile failed, srcPath or targetPath is empty. "
345 "Source Object: %{public}s, Target Object: %{public}s",
346 this->ToString(sourcePhotoInfo).c_str(),
347 this->ToString(targetPhotoInfo).c_str());
348 return E_INVALID_PATH;
349 }
350 int32_t opRet = this->CopyFile(srcPath, targetPath);
351 if (opRet != E_OK) {
352 MEDIA_ERR_LOG("Media_Operation: CopyPhoto failed, srcPath: %{public}s, targetPath: %{public}s",
353 srcPath.c_str(),
354 targetPath.c_str());
355 return opRet;
356 }
357 MediaFileUtils::ModifyFile(targetPath, dateModified / MSEC_TO_SEC);
358 MEDIA_INFO_LOG("Media_Operation: CopyPhotoFile success, srcPath: %{public}s, targetPath: %{public}s",
359 srcPath.c_str(),
360 targetPath.c_str());
361 return E_OK;
362 }
363
364 /**
365 * @brief Copy Photo File, only include the vide file related to the photo file defined in the Photos table.
366 * @return E_OK if success or not MOVING_PHOTO or video file empty,
367 * E_INVALID_PATH if the source file or target file is invalid,
368 * E_FILE_OPER_FAIL if the copy operation failed.
369 */
CopyPhotoRelatedVideoFile(const PhotoFileOperation::PhotoAssetInfo & sourcePhotoInfo,const PhotoFileOperation::PhotoAssetInfo & targetPhotoInfo)370 int32_t PhotoFileOperation::CopyPhotoRelatedVideoFile(const PhotoFileOperation::PhotoAssetInfo &sourcePhotoInfo,
371 const PhotoFileOperation::PhotoAssetInfo &targetPhotoInfo)
372 {
373 // If photoSubtype is MOVING_PHOTO, copy video file.
374 CHECK_AND_RETURN_RET(sourcePhotoInfo.isMovingPhoto, E_OK);
375 std::string srcVideoPath = sourcePhotoInfo.videoFilePath;
376 std::string targetVideoPath = targetPhotoInfo.videoFilePath;
377 int64_t dateModified = targetPhotoInfo.dateModified;
378 // If video file is empty, return E_OK. Trace log will be printed in FindVideoFilePath.
379 bool cond = (srcVideoPath.empty() || targetVideoPath.empty());
380 CHECK_AND_RETURN_RET(!cond, E_OK);
381
382 int32_t opRet = this->CopyFile(srcVideoPath, targetVideoPath);
383 CHECK_AND_RETURN_RET_LOG(opRet == E_OK, opRet,
384 "Media_Operation: CopyPhoto Video failed, srcPath: %{public}s, targetPath: %{public}s", srcVideoPath.c_str(),
385 targetVideoPath.c_str());
386 MediaFileUtils::ModifyFile(targetVideoPath, dateModified / MSEC_TO_SEC);
387 MEDIA_INFO_LOG("Media_Operation: CopyPhotoRelatedVideoFile success, srcPath: %{public}s, targetPath: %{public}s",
388 srcVideoPath.c_str(),
389 targetVideoPath.c_str());
390 return E_OK;
391 }
392
CopyPhotoRelatedData(const PhotoFileOperation::PhotoAssetInfo & sourcePhotoInfo,const PhotoFileOperation::PhotoAssetInfo & targetPhotoInfo,const std::string & srcFolder,const std::string & targetFolder)393 int32_t PhotoFileOperation::CopyPhotoRelatedData(const PhotoFileOperation::PhotoAssetInfo &sourcePhotoInfo,
394 const PhotoFileOperation::PhotoAssetInfo &targetPhotoInfo,
395 const std::string& srcFolder, const std::string& targetFolder)
396 {
397 bool cond = (srcFolder.empty() || targetFolder.empty());
398 CHECK_AND_RETURN_RET(!cond, E_OK);
399
400 if (!MediaFileUtils::IsFileExists(srcFolder)) {
401 MEDIA_ERR_LOG("Media_Operation: %{public}s doesn't exist. %{public}s",
402 srcFolder.c_str(), this->ToString(sourcePhotoInfo).c_str());
403 return E_NO_SUCH_FILE;
404 }
405 int32_t opRet = MediaFileUtils::CopyDirectory(srcFolder, targetFolder);
406 CHECK_AND_RETURN_RET_LOG(opRet == E_OK, opRet,
407 "Media_Operation: CopyPhoto extraData failed, sourceInfo: %{public}s, targetInfo: %{public}s",
408 this->ToString(sourcePhotoInfo).c_str(), this->ToString(targetPhotoInfo).c_str());
409
410 MEDIA_INFO_LOG("Media_Operation: CopyPhotoRelatedExtraData success, sourceInfo:%{public}s, targetInfo:%{public}s",
411 this->ToString(sourcePhotoInfo).c_str(), this->ToString(targetPhotoInfo).c_str());
412 return E_OK;
413 }
414
415 /**
416 * @brief Copy the Edit Data.
417 * @return E_OK if success or not edited photo.
418 * E_NO_SUCH_FILE if the source Edit Data Folder not exits.
419 * E_FAIL if the copy operation failed.
420 */
CopyPhotoRelatedExtraData(const PhotoFileOperation::PhotoAssetInfo & sourcePhotoInfo,const PhotoFileOperation::PhotoAssetInfo & targetPhotoInfo)421 int32_t PhotoFileOperation::CopyPhotoRelatedExtraData(const PhotoFileOperation::PhotoAssetInfo &sourcePhotoInfo,
422 const PhotoFileOperation::PhotoAssetInfo &targetPhotoInfo)
423 {
424 std::string srcEditDataFolder = sourcePhotoInfo.editDataFolder;
425 std::string targetEditDataFolder = targetPhotoInfo.editDataFolder;
426 return CopyPhotoRelatedData(sourcePhotoInfo, targetPhotoInfo, srcEditDataFolder, targetEditDataFolder);
427 }
428
429 /**
430 * @brief Copy the thumbnail Data.
431 * @return E_OK if success or not thumbnail folder.
432 * E_NO_SUCH_FILE if the source Edit Data Folder not exits.
433 * E_FAIL if the copy operation failed.
434 */
CopyPhotoRelatedThumbnail(const PhotoFileOperation::PhotoAssetInfo & sourcePhotoInfo,const PhotoFileOperation::PhotoAssetInfo & targetPhotoInfo)435 int32_t PhotoFileOperation::CopyPhotoRelatedThumbnail(const PhotoFileOperation::PhotoAssetInfo &sourcePhotoInfo,
436 const PhotoFileOperation::PhotoAssetInfo &targetPhotoInfo)
437 {
438 std::string srcThumbnailFolder = sourcePhotoInfo.thumbnailFolder;
439 std::string targetThumbnailFolder = targetPhotoInfo.thumbnailFolder;
440 int32_t opRet = CopyPhotoRelatedData(sourcePhotoInfo, targetPhotoInfo, srcThumbnailFolder, targetThumbnailFolder);
441 CHECK_AND_RETURN_RET_LOG(opRet == E_OK, opRet,
442 "Media_Operation: CopyPhoto thumbnail failed, srcPath: %{public}s, targetPath: %{public}s",
443 srcThumbnailFolder.c_str(), targetThumbnailFolder.c_str());
444 MEDIA_INFO_LOG("Media_Operation: CopyPhotoThumbnail success, srcThumbDir: %{public}s, targetThumbDir: %{public}s",
445 srcThumbnailFolder.c_str(), targetThumbnailFolder.c_str());
446
447 return E_OK;
448 }
449
450 /**
451 * @brief Copy File.
452 * @return E_OK if success,
453 * E_INVALID_PATH if the source file or target file is invalid,
454 * E_FILE_OPER_FAIL if the copy operation failed.
455 */
CopyFile(const std::string & srcPath,std::string & targetPath)456 int32_t PhotoFileOperation::CopyFile(const std::string &srcPath, std::string &targetPath)
457 {
458 if (srcPath.empty() || !MediaFileUtils::IsFileExists((srcPath)) || !MediaFileUtils::IsFileValid(srcPath)) {
459 MEDIA_ERR_LOG("Media_Operation: source file invalid! srcPath: %{public}s", srcPath.c_str());
460 return E_INVALID_PATH;
461 }
462 if (targetPath.empty()) {
463 MEDIA_ERR_LOG("Media_Operation: target file invalid! targetPath: %{public}s", targetPath.c_str());
464 return E_INVALID_PATH;
465 }
466 bool opRet = MediaFileUtils::CopyFileUtil(srcPath, targetPath);
467 opRet = opRet && MediaFileUtils::IsFileExists(targetPath);
468 if (!opRet) {
469 MEDIA_ERR_LOG("Media_Operation: CopyFile failed, filePath: %{public}s, errmsg: %{public}s",
470 srcPath.c_str(),
471 strerror(errno));
472 return E_FILE_OPER_FAIL;
473 }
474 return E_OK;
475 }
476
477 /**
478 * @brief ConvertFormat Photo File, include photo file, video file and edit data folder.
479 */
ConvertFormatPhoto(const std::shared_ptr<NativeRdb::ResultSet> & resultSet,const std::string & targetPath,const std::string & extension)480 int32_t PhotoFileOperation::ConvertFormatPhoto(const std::shared_ptr<NativeRdb::ResultSet> &resultSet,
481 const std::string &targetPath, const std::string &extension)
482 {
483 bool cond = (resultSet == nullptr || targetPath.empty());
484 CHECK_AND_RETURN_RET_LOG(!cond, E_FAIL,
485 "Media_Operation: ConvertFormatPhoto failed, resultSet is null or targetPath is empty");
486
487 // Build the Original Photo Asset Info
488 PhotoFileOperation::PhotoAssetInfo sourcePhotoInfo;
489 sourcePhotoInfo.displayName = GetStringVal(MediaColumn::MEDIA_NAME, resultSet);
490 sourcePhotoInfo.filePath = GetStringVal(MediaColumn::MEDIA_FILE_PATH, resultSet);
491 sourcePhotoInfo.subtype = GetInt32Val(PhotoColumn::PHOTO_SUBTYPE, resultSet);
492 int32_t effectMode = GetInt32Val(PhotoColumn::MOVING_PHOTO_EFFECT_MODE, resultSet);
493 sourcePhotoInfo.isMovingPhoto = ((sourcePhotoInfo.subtype == static_cast<int32_t>(PhotoSubType::MOVING_PHOTO)) ||
494 (effectMode == static_cast<int32_t>(MovingPhotoEffectMode::IMAGE_ONLY)));
495 sourcePhotoInfo.dateModified = GetInt64Val(MediaColumn::MEDIA_DATE_MODIFIED, resultSet);
496 sourcePhotoInfo.videoFilePath = this->FindVideoFilePath(sourcePhotoInfo);
497 sourcePhotoInfo.editDataFolder = this->FindEditDataFolder(sourcePhotoInfo);
498 // Build the Target Photo Asset Info
499 PhotoFileOperation::PhotoAssetInfo targetPhotoInfo;
500 targetPhotoInfo.displayName = sourcePhotoInfo.displayName;
501 targetPhotoInfo.filePath = targetPath;
502 targetPhotoInfo.subtype = sourcePhotoInfo.subtype;
503 targetPhotoInfo.dateModified = sourcePhotoInfo.dateModified;
504 // No need to copy video file if the Original Photo is not a moving photo.
505 if (!sourcePhotoInfo.videoFilePath.empty()) {
506 targetPhotoInfo.videoFilePath = this->GetVideoFilePath(targetPhotoInfo);
507 }
508 // No need to copy edit data folder if the Original Photo is not edited.
509 if (!sourcePhotoInfo.editDataFolder.empty()) {
510 targetPhotoInfo.editDataFolder = this->BuildEditDataFolder(targetPhotoInfo);
511 }
512 MEDIA_INFO_LOG("Media_Operation: sourcePhotoInfo: %{public}s, targetPhotoInfo: %{public}s, extension: %{public}s",
513 this->ToString(sourcePhotoInfo).c_str(), this->ToString(targetPhotoInfo).c_str(), extension.c_str());
514 return this->ConvertFormatPhoto(sourcePhotoInfo, targetPhotoInfo, extension);
515 }
516
ConvertFormatPhoto(const PhotoAssetInfo & sourcePhotoInfo,const PhotoAssetInfo & targetPhotoInfo,const std::string & extension)517 int32_t PhotoFileOperation::ConvertFormatPhoto(const PhotoAssetInfo &sourcePhotoInfo,
518 const PhotoAssetInfo &targetPhotoInfo, const std::string &extension)
519 {
520 // copy renderings, need convert format
521 int32_t opRet = this->ConvertFormatFile(sourcePhotoInfo.filePath, targetPhotoInfo.filePath,
522 targetPhotoInfo.dateModified, extension);
523 CHECK_AND_RETURN_RET_LOG(opRet == E_OK, opRet, "ConvertFormat File failed");
524 MEDIA_INFO_LOG("ConvertFormat File success, srcFile: %{public}s, dstFile: %{public}s, extension: %{public}s",
525 sourcePhotoInfo.filePath.c_str(), targetPhotoInfo.filePath.c_str(), extension.c_str());
526
527 // copy moving photo
528 if (sourcePhotoInfo.isMovingPhoto) {
529 opRet = this->ConvertFormatFile(sourcePhotoInfo.videoFilePath, targetPhotoInfo.videoFilePath,
530 targetPhotoInfo.dateModified, "");
531 CHECK_AND_RETURN_RET_LOG(opRet == E_OK, opRet, "ConvertFormat Video failed");
532 MEDIA_INFO_LOG("ConvertFormat Video success, srcVideo: %{public}s, dstVideo: %{public}s",
533 sourcePhotoInfo.videoFilePath.c_str(), targetPhotoInfo.videoFilePath.c_str());
534 }
535
536 // copy editData folder, source.heic need convert format, other copy
537 opRet = this->ConvertFormatPhotoExtraData(sourcePhotoInfo.editDataFolder, targetPhotoInfo.editDataFolder,
538 extension);
539 CHECK_AND_RETURN_RET_LOG(opRet == E_OK, opRet, "ConvertFormat PhotoExtraData failed");
540 MEDIA_INFO_LOG("ConvertFormat ExtraData success, srcExtraData: %{public}s, dstExtraData: %{public}s, "
541 "extension: %{public}s", sourcePhotoInfo.editDataFolder.c_str(), targetPhotoInfo.editDataFolder.c_str(),
542 extension.c_str());
543
544 return E_OK;
545 }
546
ConvertFormatFile(const std::string & srcFilePath,const std::string & dstFilePath,const int64_t dateModified,const std::string & extension)547 int32_t PhotoFileOperation::ConvertFormatFile(const std::string &srcFilePath, const std::string &dstFilePath,
548 const int64_t dateModified, const std::string &extension)
549 {
550 // If File Path is empty, return E_INVALID_PATH.
551 if (srcFilePath.empty() || dstFilePath.empty() || !MediaFileUtils::IsFileExists(srcFilePath) ||
552 !MediaFileUtils::IsFileValid(srcFilePath)) {
553 MEDIA_ERR_LOG("Media_Operation: check srcPath or targetPath failed");
554 return E_INVALID_PATH;
555 }
556
557 bool ret = false;
558 if (!extension.empty()) {
559 ret = MediaFileUtils::ConvertFormatCopy(srcFilePath, dstFilePath, extension);
560 } else {
561 ret = MediaFileUtils::CopyFileUtil(srcFilePath, dstFilePath);
562 }
563 if (!ret || !MediaFileUtils::IsFileExists(dstFilePath)) {
564 MEDIA_INFO_LOG("Media_Operation: ConvertFormatFile failed, srcFilePath: %{public}s, dstFilePath: %{public}s, "
565 "extension: %{public}s", srcFilePath.c_str(), dstFilePath.c_str(), extension.c_str());
566 return E_FILE_OPER_FAIL;
567 }
568
569 MediaFileUtils::ModifyFile(dstFilePath, dateModified / MSEC_TO_SEC);
570 return E_OK;
571 }
572
ConvertFormatPhotoExtraData(const std::string & srcPath,const std::string & dstPath,const std::string & extension)573 int32_t PhotoFileOperation::ConvertFormatPhotoExtraData(const std::string &srcPath, const std::string &dstPath,
574 const std::string &extension)
575 {
576 if (srcPath.empty() || dstPath.empty()) {
577 return E_OK;
578 }
579 if (!MediaFileUtils::IsFileExists(srcPath)) {
580 MEDIA_ERR_LOG("Media_Operation: %{public}s doesn't exist", srcPath.c_str());
581 return E_NO_SUCH_FILE;
582 }
583
584 int32_t ret = MediaFileUtils::ConvertFormatExtraDataDirectory(srcPath, dstPath, extension);
585 if (ret != E_OK) {
586 MEDIA_ERR_LOG("ConvertFormatExtraDataDirectory failed, srcPath: %{public}s, dstPath: %{public}s, "
587 "extension: %{public}s", srcPath.c_str(), dstPath.c_str(), extension.c_str());
588 return ret;
589 }
590 return E_OK;
591 }
592 // LCOV_EXCL_STOP
593 } // namespace OHOS::Media