1 /*
2 * Copyright (c) 2025 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 "Media_Client"
16
17 #include "cloud_album_data_convert.h"
18
19 #include <string>
20 #include <sys/stat.h>
21 #include <sys/time.h>
22 #include <unistd.h>
23
24 #include "directory_ex.h"
25 #include "file_ex.h"
26 #include "media_log.h"
27 #include "medialibrary_errno.h"
28 #include "cloud_media_sync_const.h"
29 #include "media_file_utils.h"
30 #include "moving_photo_file_utils.h"
31 #include "photo_file_utils.h"
32
33 namespace OHOS::Media::CloudSync {
34 const std::string CloudAlbumDataConvert::recordType_ = "album";
CloudAlbumDataConvert(CloudAlbumOperationType type)35 CloudAlbumDataConvert::CloudAlbumDataConvert(CloudAlbumOperationType type) : type_(type)
36 {}
37
HandleAlbumName(std::map<std::string,MDKRecordField> & map,const CloudMdkRecordPhotoAlbumVo & albumData)38 int32_t CloudAlbumDataConvert::HandleAlbumName(
39 std::map<std::string, MDKRecordField> &map, const CloudMdkRecordPhotoAlbumVo &albumData)
40 {
41 int32_t albumType = albumData.albumType;
42 if (albumType == AlbumType::SOURCE) {
43 std::string lpath = albumData.lpath;
44 if (albumData.isInWhiteList) {
45 std::string dualName = albumData.dualAlbumName;
46 std::string albumNameEn = albumData.albumNameEn;
47 map["localPath"] = MDKRecordField(lpath);
48 if (!dualName.empty()) {
49 map["albumName"] = MDKRecordField(dualName);
50 return E_OK;
51 }
52 if (!albumNameEn.empty()) {
53 map["albumName"] = MDKRecordField(albumNameEn);
54 return E_OK;
55 }
56 }
57 }
58 map["albumName"] = MDKRecordField(albumData.albumName);
59 return E_OK;
60 }
61
62 /* properties - general */
HandleGeneral(std::map<std::string,MDKRecordField> & map,const CloudMdkRecordPhotoAlbumVo & albumData)63 int32_t CloudAlbumDataConvert::HandleGeneral(
64 std::map<std::string, MDKRecordField> &map, const CloudMdkRecordPhotoAlbumVo &albumData)
65 {
66 map[PhotoAlbumColumns::ALBUM_TYPE] = MDKRecordField(albumData.albumType);
67 map[PhotoAlbumColumns::ALBUM_SUBTYPE] = MDKRecordField(albumData.albumSubtype);
68 map[PhotoAlbumColumns::ALBUM_DATE_MODIFIED] = MDKRecordField(albumData.dateModified);
69 map[PhotoAlbumColumns::ALBUM_DATE_ADDED] = MDKRecordField(albumData.dateAdded);
70 map[PhotoAlbumColumns::ALBUM_BUNDLE_NAME] = MDKRecordField(albumData.bundleName);
71 map[PhotoAlbumColumns::ALBUM_LOCAL_LANGUAGE] = MDKRecordField(albumData.localLanguage);
72 map[PhotoAlbumColumns::COVER_URI_SOURCE] = MDKRecordField(albumData.coverUriSource);
73 return E_OK;
74 }
75
HandleProperties(std::shared_ptr<MDKRecord> & record,std::map<std::string,MDKRecordField> & data,const CloudMdkRecordPhotoAlbumVo & albumData)76 int32_t CloudAlbumDataConvert::HandleProperties(std::shared_ptr<MDKRecord> &record,
77 std::map<std::string, MDKRecordField> &data, const CloudMdkRecordPhotoAlbumVo &albumData)
78 {
79 std::map<std::string, MDKRecordField> map;
80 /* general */
81 CHECK_AND_RETURN_RET(HandleGeneral(map, albumData) == E_OK, E_HANDLE_GENERAL_FAILED);
82 /* set map */
83 data["properties"] = MDKRecordField(map);
84 return E_OK;
85 }
86
HandleAttributes(std::map<std::string,MDKRecordField> & data,const CloudMdkRecordPhotoAlbumVo & albumData)87 int32_t CloudAlbumDataConvert::HandleAttributes(std::map<std::string, MDKRecordField> &data,
88 const CloudMdkRecordPhotoAlbumVo &albumData)
89 {
90 std::map<std::string, MDKRecordField> map;
91 if (albumData.coverUriSource == CoverUriSource::MANUAL_CLOUD_COVER) {
92 map[PhotoAlbumColumns::COVER_URI_SOURCE] = MDKRecordField(albumData.coverUriSource);
93 map[PhotoAlbumColumns::COVER_CLOUD_ID] = MDKRecordField(albumData.coverCloudId);
94 }
95 /* set map */
96 data["attributes"] = MDKRecordField(map);
97 return E_OK;
98 }
99
HandleAlbumLogicType(std::map<std::string,MDKRecordField> & map,const CloudMdkRecordPhotoAlbumVo & albumData)100 int32_t CloudAlbumDataConvert::HandleAlbumLogicType(
101 std::map<std::string, MDKRecordField> &map, const CloudMdkRecordPhotoAlbumVo &albumData)
102 {
103 map["logicType"] = MDKRecordField(LogicType::PHYSICAL);
104 return E_OK;
105 }
106
HandleType(std::map<std::string,MDKRecordField> & map,const CloudMdkRecordPhotoAlbumVo & albumData)107 int32_t CloudAlbumDataConvert::HandleType(
108 std::map<std::string, MDKRecordField> &map, const CloudMdkRecordPhotoAlbumVo &albumData)
109 {
110 map["type"] = MDKRecordField(AlbumType::NORMAL);
111 return E_OK;
112 }
113
HandleAlbumId(std::map<std::string,MDKRecordField> & map,const CloudMdkRecordPhotoAlbumVo & albumData)114 int32_t CloudAlbumDataConvert::HandleAlbumId(
115 std::map<std::string, MDKRecordField> &map, const CloudMdkRecordPhotoAlbumVo &albumData)
116 {
117 map["albumId"] = MDKRecordField(albumData.albumId);
118 return E_OK;
119 }
120
HandleHashCode(const std::string & str)121 int32_t HandleHashCode(const std::string &str) __attribute__((no_sanitize("signed-integer-overflow")))
122 {
123 int32_t hash = 0;
124 for (uint32_t i = 0; i < str.length(); i++) {
125 char c = str.at(i);
126 hash = hash * HASH_VLAUE + c;
127 }
128 return hash;
129 }
130
HandleRecordId(std::shared_ptr<MDKRecord> record,const CloudMdkRecordPhotoAlbumVo & albumData)131 int32_t CloudAlbumDataConvert::HandleRecordId(
132 std::shared_ptr<MDKRecord> record, const CloudMdkRecordPhotoAlbumVo &albumData)
133 {
134 std::map<std::string, MDKRecordField> data;
135 record->GetRecordData(data);
136 std::string recordId = albumData.cloudId;
137 if (!recordId.empty()) {
138 record->SetRecordId(recordId);
139 return E_OK;
140 }
141 std::string lpath = albumData.lpath;
142 if (albumData.isInWhiteList) {
143 std::string cloudId = albumData.albumPluginCloudId;
144 if (!cloudId.empty()) {
145 record->SetRecordId(cloudId);
146 return E_OK;
147 }
148 }
149 int64_t timeadded = albumData.dateAdded;
150 if (timeadded == 0) {
151 struct timeval tv;
152 gettimeofday(&tv, nullptr);
153 timeadded = tv.tv_sec * MILLISECOND_TO_SECOND + tv.tv_usec / MILLISECOND_TO_SECOND;
154 }
155 std::transform(lpath.begin(), lpath.end(), lpath.begin(), ::tolower);
156 int32_t hashValue = HandleHashCode(lpath);
157 std::string cloudId = "default-album-200-" + std::to_string(hashValue) + "-" + std::to_string(timeadded);
158 MEDIA_INFO_LOG("lpath is %{public}s, cloudid is %{private}s", lpath.c_str(), cloudId.c_str());
159 record->SetRecordId(cloudId);
160 return E_OK;
161 }
162
HandlePath(std::map<std::string,MDKRecordField> & map,const CloudMdkRecordPhotoAlbumVo & albumData)163 int32_t CloudAlbumDataConvert::HandlePath(
164 std::map<std::string, MDKRecordField> &map, const CloudMdkRecordPhotoAlbumVo &albumData)
165 {
166 std::string val = albumData.lpath;
167 if (!val.empty()) {
168 map["isLogic"] = MDKRecordField(false);
169 }
170 map["localPath"] = MDKRecordField(val);
171 return E_OK;
172 }
173
174 /* record id */
FillRecordId(std::shared_ptr<MDKRecord> record,const CloudMdkRecordPhotoAlbumVo & albumData)175 int32_t CloudAlbumDataConvert::FillRecordId(
176 std::shared_ptr<MDKRecord> record, const CloudMdkRecordPhotoAlbumVo &albumData)
177 {
178 std::string val = albumData.cloudId;
179 record->SetRecordId(val);
180 return E_OK;
181 }
182
HandleEmptyShow(std::shared_ptr<MDKRecord> record,std::map<std::string,MDKRecordField> & data,const CloudMdkRecordPhotoAlbumVo & albumData)183 void CloudAlbumDataConvert::HandleEmptyShow(std::shared_ptr<MDKRecord> record,
184 std::map<std::string, MDKRecordField> &data, const CloudMdkRecordPhotoAlbumVo &albumData)
185 {
186 if (record->GetRecordId() == DEFAULT_HIDE_ALBUM_CLOUDID) {
187 std::map<std::string, MDKRecordField> map = data["properties"];
188 map["emptyShow"] = MDKRecordField("1");
189 data["properties"] = MDKRecordField(map);
190 record->SetRecordData(data);
191 }
192 }
193
ConvertToDoubleScreenshot(std::shared_ptr<MDKRecord> record,std::map<std::string,MDKRecordField> & data)194 int32_t CloudAlbumDataConvert::ConvertToDoubleScreenshot(
195 std::shared_ptr<MDKRecord> record, std::map<std::string, MDKRecordField> &data)
196 {
197 std::string lPath;
198 if (data.find("localPath") == data.end() || data.at("localPath").GetString(lPath) != MDKLocalErrorCode::NO_ERROR) {
199 MEDIA_ERR_LOG("ConvertToDoubleScreenshot lpath error");
200 return E_MEDIA_CLOUD_ARGS_INVAILD;
201 }
202
203 MEDIA_INFO_LOG("ConvertToDoubleScreenshot lpath:%{public}s", lPath.c_str());
204 if (lPath == DEFAULT_SCREENSHOT_LPATH_EN) {
205 data["albumName"] = MDKRecordField(SCREEN_SHOT_AND_RECORDER_EN);
206 record->SetRecordId(DEFAULT_SCREENSHOT_CLOUDID);
207 }
208
209 if (lPath == DEFAULT_SCREENRECORDS_LPATH) {
210 data["localPath"] = MDKRecordField(DEFAULT_SCREENSHOT_LPATH_EN);
211 data["albumName"] = MDKRecordField(SCREEN_SHOT_AND_RECORDER_EN);
212 record->SetRecordId(DEFAULT_SCREENSHOT_CLOUDID);
213 }
214 return E_OK;
215 }
216
ConvertToMdkRecord(const CloudMdkRecordPhotoAlbumVo & upLoadRecord)217 std::shared_ptr<MDKRecord> CloudAlbumDataConvert::ConvertToMdkRecord(const CloudMdkRecordPhotoAlbumVo &upLoadRecord)
218 {
219 std::shared_ptr<MDKRecord> record = std::make_shared<MDKRecord>();
220 std::map<std::string, MDKRecordField> data;
221 /* basic */
222 CHECK_AND_RETURN_RET_LOG(HandleAlbumName(data, upLoadRecord) == E_OK, nullptr, "HandleAlbumName failed");
223 CHECK_AND_RETURN_RET_LOG(HandleAlbumLogicType(data, upLoadRecord) == E_OK, nullptr, "HandleAlbumLogicType failed");
224 CHECK_AND_RETURN_RET_LOG(HandleType(data, upLoadRecord) == E_OK, nullptr, "HandleType failed");
225
226 /* properties */
227 CHECK_AND_RETURN_RET_LOG(HandleProperties(record, data, upLoadRecord) == E_OK, nullptr, "HandleProperties failed");
228 /* attributes */
229 CHECK_AND_RETURN_RET_LOG(HandleAttributes(data, upLoadRecord) == E_OK, nullptr, "HandleAttributes failed");
230 /* control info */
231 record->SetRecordType(recordType_);
232 if (type_ == PHOTO_ALBUM_CREATE) {
233 record->SetNewCreate(true);
234 CHECK_AND_RETURN_RET_LOG(HandleAlbumId(data, upLoadRecord) == E_OK, nullptr, "HandleAlbumId failed");
235 CHECK_AND_RETURN_RET_LOG(HandleRecordId(record, upLoadRecord) == E_OK, nullptr, "HandleRecordId failed");
236 CHECK_AND_RETURN_RET_LOG(HandlePath(data, upLoadRecord) == E_OK, nullptr, "HandlePath failed");
237 } else {
238 int32_t ret = FillRecordId(record, upLoadRecord);
239 if (ret != E_OK) {
240 MEDIA_ERR_LOG("fill record id err %{public}d", ret);
241 return nullptr;
242 }
243 data["albumId"] = MDKRecordField(record->GetRecordId());
244 }
245 HandleEmptyShow(record, data, upLoadRecord);
246 /* set data */
247 ConvertToDoubleScreenshot(record, data);
248 record->SetRecordData(data);
249
250 return record;
251 }
252
ConvertErrorTypeDetails(const MDKRecordOperResult & result,std::vector<CloudErrorDetail> & errorDetails)253 void CloudAlbumDataConvert::ConvertErrorTypeDetails(
254 const MDKRecordOperResult &result, std::vector<CloudErrorDetail> &errorDetails)
255 {
256 auto errorType = result.GetDKError();
257 if (errorType.errorDetails.empty()) {
258 return;
259 }
260 for (const auto &element : errorType.errorDetails) {
261 CloudErrorDetail detail;
262 detail.domain = element.domain;
263 detail.reason = element.reason;
264 detail.errorCode = element.errorCode;
265 detail.description = element.description;
266 detail.errorPos = element.errorPos;
267 detail.errorParam = element.errorParam;
268 detail.detailCode = element.detailCode;
269 errorDetails.push_back(detail);
270 }
271 }
272
ConvertToOnCreateRecord(const std::string & cloudId,const MDKRecordOperResult & result,OnCreateRecordsAlbumReqBodyAlbumData & record)273 int32_t CloudAlbumDataConvert::ConvertToOnCreateRecord(
274 const std::string &cloudId, const MDKRecordOperResult &result, OnCreateRecordsAlbumReqBodyAlbumData &record)
275 {
276 MDKRecordAlbumData data = MDKRecordAlbumData(result.GetDKRecord());
277 record.cloudId = cloudId;
278 std::string newCloudId = data.GetCloudId().value_or("");
279 record.newCloudId = newCloudId;
280 record.isSuccess = result.IsSuccess();
281 record.serverErrorCode = result.GetDKError().serverErrorCode;
282 ConvertErrorTypeDetails(result, record.errorDetails);
283 return E_OK;
284 }
285
286
BuildModifyRecord(const std::string & cloudId,const MDKRecordOperResult & result,OnMdirtyAlbumRecord & record)287 int32_t CloudAlbumDataConvert::BuildModifyRecord(
288 const std::string &cloudId, const MDKRecordOperResult &result, OnMdirtyAlbumRecord &record)
289 {
290 MDKRecordAlbumData data = MDKRecordAlbumData(result.GetDKRecord());
291 record.cloudId = cloudId;
292 record.isSuccess = result.IsSuccess();
293 record.serverErrorCode = result.GetDKError().serverErrorCode;
294 ConvertErrorTypeDetails(result, record.errorDetails);
295 return E_OK;
296 }
297 } // namespace OHOS::Media::CloudSync