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 #include <string>
16 #include <vector>
17 
18 #include "photos_restore.h"
19 #include "backup_const.h"
20 #include "backup_file_utils.h"
21 #include "userfile_manager_types.h"
22 #include "rdb_store.h"
23 #include "result_set_utils.h"
24 #include "media_log.h"
25 #include "photo_album_dao.h"
26 #include "album_plugin_config.h"
27 #include "backup_file_utils.h"
28 #include "mimetype_utils.h"
29 
30 namespace OHOS::Media {
31 static const int32_t CLOUD_ENHANCEMENT_ALBUM = 1;
32 static const int32_t DUAL_ENHANCEMENT_PHOTO_QUALITY = 120;
33 static const int32_t SINGLE_CLOUD_ENHANCEMENT_PHOTO = 120;
34 
35 /**
36  * @brief Get the gallery_media to restore to Photos.
37  */
GetGalleryMedia(int32_t offset,int pageSize,bool shouldIncludeSd,bool hasLowQualityImage)38 std::shared_ptr<NativeRdb::ResultSet> PhotosRestore::GetGalleryMedia(
39     int32_t offset, int pageSize, bool shouldIncludeSd, bool hasLowQualityImage)
40 {
41     return this->galleryMediaDao_.GetGalleryMedia(offset, pageSize, shouldIncludeSd, hasLowQualityImage);
42 }
43 
44 /**
45  * @brief Get the row count of gallery_media.
46  */
GetGalleryMediaCount(bool shouldIncludeSd,bool hasLowQualityImage)47 int32_t PhotosRestore::GetGalleryMediaCount(bool shouldIncludeSd, bool hasLowQualityImage)
48 {
49     return this->galleryMediaDao_.GetGalleryMediaCount(shouldIncludeSd, hasLowQualityImage);
50 }
51 
52 /**
53  * @brief Get the PhotoAlbum basic info.
54  */
FindAlbumInfo(const FileInfo & fileInfo)55 PhotoAlbumDao::PhotoAlbumRowData PhotosRestore::FindAlbumInfo(const FileInfo &fileInfo)
56 {
57     std::string lPath = fileInfo.lPath;
58     // Scenario 2, WHEN FileInfo is in hidden album, THEN override lPath to the folder in sourcePath.
59     // Scenario 3, WHEN FileInfo is not belongs to any album, THEN override lPath to the folder in sourcePath.
60     if (fileInfo.lPath.empty() || this->ToLower(fileInfo.lPath) == this->ToLower(GALLERT_HIDDEN_ALBUM)) {
61         lPath = this->photoAlbumDao_.ParseSourcePathToLPath(fileInfo.sourcePath);
62         MEDIA_INFO_LOG("Media_Restore: fix lPath of album.fileInfo.lPath: %{public}s, "
63                        "lPathFromSourcePath: %{public}s, lowercase: %{public}s, FileInfo Object: %{public}s",
64             fileInfo.lPath.c_str(),
65             lPath.c_str(),
66             this->ToLower(lPath).c_str(),
67             this->ToString(fileInfo).c_str());
68     }
69     PhotoAlbumDao::PhotoAlbumRowData albumInfo;
70     // Scenario 1, WHEN FileInfo is in /Pictures/Screenshots and Video type, THEN redirect to /Pictures/Screenrecords
71     if (this->ToLower(lPath) == this->ToLower(AlbumPlugin::LPATH_SCREEN_SHOTS) &&
72         fileInfo.fileType == MediaType::MEDIA_TYPE_VIDEO) {
73         albumInfo = this->photoAlbumDao_.BuildAlbumInfoOfRecorders();
74         albumInfo = this->photoAlbumDao_.GetOrCreatePhotoAlbum(albumInfo);
75         MEDIA_INFO_LOG("Media_Restore: screenshots redirect to screenrecords, fileInfo.lPath: %{public}s, "
76                        "lPathForScreenshot: %{public}s, Object: %{public}s, albumInfo: %{public}s",
77             fileInfo.lPath.c_str(),
78             lPath.c_str(),
79             this->ToString(fileInfo).c_str(),
80             this->photoAlbumDao_.ToString(albumInfo).c_str());
81         return albumInfo;
82     }
83     albumInfo = this->photoAlbumDao_.BuildAlbumInfoByLPath(lPath);
84     return this->photoAlbumDao_.GetOrCreatePhotoAlbum(albumInfo);
85 }
86 
87 /**
88  * @brief Get the PhotoAlbum basic info.
89  */
FindAlbumId(const FileInfo & fileInfo)90 int32_t PhotosRestore::FindAlbumId(const FileInfo &fileInfo)
91 {
92     PhotoAlbumDao::PhotoAlbumRowData albumInfo = this->FindAlbumInfo(fileInfo);
93     if (albumInfo.lPath.empty()) {
94         MEDIA_ERR_LOG("Can not find PhotoAlbum. fileInfo.lPath= %{public}s, fileInfo.sourcePath= %{public}s",
95             fileInfo.lPath.c_str(),
96             fileInfo.sourcePath.c_str());
97     }
98     return albumInfo.albumId;
99 }
100 
101 /**
102  * @brief find lPath by FileInfo.
103  */
FindlPath(const FileInfo & fileInfo)104 std::string PhotosRestore::FindlPath(const FileInfo &fileInfo)
105 {
106     PhotoAlbumDao::PhotoAlbumRowData albumInfo = this->FindAlbumInfo(fileInfo);
107     if (albumInfo.lPath.empty()) {
108         MEDIA_ERR_LOG("Can not find PhotoAlbum. fileInfo.lPath= %{public}s, fileInfo.sourcePath= %{public}s",
109             fileInfo.lPath.c_str(),
110             fileInfo.sourcePath.c_str());
111     }
112     return albumInfo.lPath;
113 }
114 
115 /**
116  * @brief Find PackageName by FileInfo.
117  */
FindPackageName(const FileInfo & fileInfo)118 std::string PhotosRestore::FindPackageName(const FileInfo &fileInfo)
119 {
120     PhotoAlbumDao::PhotoAlbumRowData albumInfo = this->FindAlbumInfo(fileInfo);
121     if (albumInfo.lPath.empty()) {
122         MEDIA_ERR_LOG("Can not find PhotoAlbum. fileInfo.lPath= %{public}s, fileInfo.sourcePath= %{public}s",
123             fileInfo.lPath.c_str(),
124             fileInfo.sourcePath.c_str());
125     }
126     return albumInfo.albumName;
127 }
128 
129 /**
130  * @brief Find BundleName by FileInfo.
131  */
FindBundleName(const FileInfo & fileInfo)132 std::string PhotosRestore::FindBundleName(const FileInfo &fileInfo)
133 {
134     PhotoAlbumDao::PhotoAlbumRowData albumInfo = this->FindAlbumInfo(fileInfo);
135     if (albumInfo.lPath.empty()) {
136         MEDIA_ERR_LOG("Can not find PhotoAlbum. fileInfo.lPath= %{public}s, fileInfo.sourcePath= %{public}s",
137             fileInfo.lPath.c_str(),
138             fileInfo.sourcePath.c_str());
139     }
140     return albumInfo.bundleName;
141 }
142 
143 /**
144  * @brief Find BurstKey by FileInfo.
145  */
FindBurstKey(const FileInfo & fileInfo)146 std::string PhotosRestore::FindBurstKey(const FileInfo &fileInfo)
147 {
148     if (fileInfo.burstKey.size() > 0) {
149         return fileInfo.burstKey;
150     }
151     return "";
152 }
153 
154 /**
155  * @brief Find Dirty by FileInfo.
156  */
FindDirty(const FileInfo & fileInfo)157 int32_t PhotosRestore::FindDirty(const FileInfo &fileInfo)
158 {
159     return static_cast<int32_t>(DirtyTypes::TYPE_NEW);
160 }
161 
162 /**
163  * @brief Find burst_cover_level by FileInfo.
164  */
FindBurstCoverLevel(const FileInfo & fileInfo)165 int32_t PhotosRestore::FindBurstCoverLevel(const FileInfo &fileInfo)
166 {
167     // identify burst photo
168     if (fileInfo.isBurst == static_cast<int32_t>(BurstCoverLevelType::COVER) ||
169         fileInfo.isBurst == static_cast<int32_t>(BurstCoverLevelType::MEMBER)) {
170         return fileInfo.isBurst;
171     }
172     return static_cast<int32_t>(BurstCoverLevelType::COVER);
173 }
174 
175 /**
176  * @brief Find subtype by FileInfo.
177  */
FindSubtype(const FileInfo & fileInfo)178 int32_t PhotosRestore::FindSubtype(const FileInfo &fileInfo)
179 {
180     if (fileInfo.burstKey.size() > 0) {
181         return static_cast<int32_t>(PhotoSubType::BURST);
182     }
183     if (BackupFileUtils::IsLivePhoto(fileInfo)) {
184         return static_cast<int32_t>(PhotoSubType::MOVING_PHOTO);
185     }
186     return static_cast<int32_t>(PhotoSubType::DEFAULT);
187 }
188 
189 /**
190  * @brief Find date_trashed by FileInfo.
191  */
FindDateTrashed(const FileInfo & fileInfo)192 int64_t PhotosRestore::FindDateTrashed(const FileInfo &fileInfo)
193 {
194     // prevent Photos marked as deleted when it's in use.
195     if (fileInfo.recycleFlag == 0) {
196         return 0;
197     }
198     // LOG INFO for analyser.
199     if (fileInfo.recycledTime != 0) {
200         string fileName = fileInfo.displayName;
201         MEDIA_WARN_LOG("the file :%{public}s is trash.", BackupFileUtils::GarbleFileName(fileName).c_str());
202     }
203     return fileInfo.recycledTime;
204 }
205 
206 /**
207  * @brief Get duplicate data in gallery db.
208  */
GetDuplicateData(int32_t duplicateDataCount)209 void PhotosRestore::GetDuplicateData(int32_t duplicateDataCount)
210 {
211     if (duplicateDataCount <= 0) {
212         return;
213     }
214     std::string querySql = this->SQL_GALLERY_MEDIA_QUERY_DUPLICATE_DATA;
215     int rowCount = 0;
216     int offset = 0;
217     int pageSize = 200;
218     do {
219         std::vector<NativeRdb::ValueObject> params = {offset, pageSize};
220         if (this->galleryRdb_ == nullptr) {
221             MEDIA_ERR_LOG("Media_Restore: galleryRdb_ is null.");
222             break;
223         }
224         auto resultSet = this->galleryRdb_->QuerySql(querySql, params);
225         if (resultSet == nullptr) {
226             MEDIA_ERR_LOG("Query resultSql is null.");
227             break;
228         }
229         while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
230             std::string data = GetStringVal(GALLERY_FILE_DATA, resultSet);
231             int32_t count = GetInt32Val(CUSTOM_COUNT, resultSet);
232             this->duplicateDataUsedCountMap_[data] = 0;
233             MEDIA_INFO_LOG("Get duplicate data: %{public}s, count: %{public}d",
234                 BackupFileUtils::GarbleFilePath(data, DEFAULT_RESTORE_ID).c_str(),
235                 count);
236         }
237         // Check if there are more rows to fetch.
238         resultSet->GetRowCount(rowCount);
239         offset += pageSize;
240     } while (rowCount > 0);
241 }
242 
243 /**
244  * @brief Check if it is duplicate data in gallery db.
245  */
IsDuplicateData(const std::string & data)246 bool PhotosRestore::IsDuplicateData(const std::string &data)
247 {
248     std::lock_guard<mutex> lock(this->duplicateDataUsedCountMutex_);
249     if (this->duplicateDataUsedCountMap_.count(data) == 0) {
250         return false;
251     }
252     this->duplicateDataUsedCountMap_[data]++;
253     return this->duplicateDataUsedCountMap_.at(data) > 1;
254 }
255 
256 /**
257  * @brief Find PhotoQuality by FileInfo.
258  */
FindPhotoQuality(const FileInfo & fileInfo)259 int32_t PhotosRestore::FindPhotoQuality(const FileInfo &fileInfo)
260 {
261     if (fileInfo.photoQuality == 1 && fileInfo.fileType == MediaType::MEDIA_TYPE_VIDEO) {
262         return 0;
263     }
264     return fileInfo.photoQuality;
265 }
266 
267 /**
268  * @brief Find suffix of displayName. include dot, e.g. ".jpg"
269  * @return return the suffix of displayName. "" if not found.
270  */
GetSuffix(const std::string & displayName)271 std::string PhotosRestore::GetSuffix(const std::string &displayName)
272 {
273     size_t dotPos = displayName.rfind('.');
274     if (dotPos != std::string::npos) {
275         return this->ToLower(displayName.substr(dotPos + 1));  // without dot, e.g. "jpg"
276     }
277     return "";
278 }
279 
280 /**
281  * @brief Find media_type by FileInfo.
282  */
FindMediaType(const FileInfo & fileInfo)283 int32_t PhotosRestore::FindMediaType(const FileInfo &fileInfo)
284 {
285     int32_t dualMediaType = fileInfo.fileType;
286     if (dualMediaType == DUAL_MEDIA_TYPE::IMAGE_TYPE || dualMediaType == DUAL_MEDIA_TYPE::VIDEO_TYPE) {
287         return dualMediaType == DUAL_MEDIA_TYPE::VIDEO_TYPE ? MediaType::MEDIA_TYPE_VIDEO : MediaType::MEDIA_TYPE_IMAGE;
288     }
289     std::string suffix = this->GetSuffix(fileInfo.displayName);
290     MediaType mediaType = MimeTypeUtils::GetMediaTypeFromMimeType(MimeTypeUtils::GetMimeTypeFromExtension(suffix));
291     MEDIA_INFO_LOG("Media_Restore: correct mediaType from %{public}d to %{public}d, displayName: %{public}s",
292         fileInfo.fileType,
293         mediaType,
294         fileInfo.displayName.c_str());
295     return mediaType;
296 }
297 
298 /**
299  * @brief Find source_path for the target device by FileInfo.
300  */
FindSourcePath(const FileInfo & fileInfo)301 std::string PhotosRestore::FindSourcePath(const FileInfo &fileInfo)
302 {
303     if (!fileInfo.sourcePath.empty()) {
304         return fileInfo.sourcePath;
305     }
306     std::string lPath = "/Pictures/其它";
307     if (!fileInfo.lPath.empty()) {
308         lPath = fileInfo.lPath;
309     } else {
310         MEDIA_ERR_LOG("Media_Restore: fileInfo.lPath is empty. Use default lPath: %{public}s", lPath.c_str());
311     }
312     return this->SOURCE_PATH_PREFIX + lPath + "/" + fileInfo.displayName;
313 }
314 
315 /**
316  * @brief Find enhancement photo quality for the target device by FileInfo.
317  */
FindStrongAssociation(const FileInfo & fileInfo)318 int32_t PhotosRestore::FindStrongAssociation(const FileInfo &fileInfo)
319 {
320     if (fileInfo.photoQuality == DUAL_ENHANCEMENT_PHOTO_QUALITY) {
321         return CLOUD_ENHANCEMENT_ALBUM;
322     }
323     return 0;
324 }
325 
326 /**
327  * @brief Find cloud enhancement available for the target device by FileInfo.
328  */
FindCeAvailable(const FileInfo & fileInfo)329 int32_t PhotosRestore::FindCeAvailable(const FileInfo &fileInfo)
330 {
331     if (fileInfo.photoQuality == DUAL_ENHANCEMENT_PHOTO_QUALITY) {
332         return SINGLE_CLOUD_ENHANCEMENT_PHOTO;
333     }
334     return 0;
335 }
336 }  // namespace OHOS::Media