• 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 #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