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 "media_library_tab_old_photos_client.h"
16
17 #include <limits>
18 #include <string>
19 #include <vector>
20 #include <unordered_map>
21
22 #include "userfilemgr_uri.h"
23 #include "media_column.h"
24 #include "media_log.h"
25 #include "media_old_photos_column.h"
26 #include "medialibrary_errno.h"
27 #include "result_set_utils.h"
28 #include "datashare_helper.h"
29
30 using namespace std;
31
32 namespace OHOS::Media {
GetUrisByOldUris(std::vector<std::string> & uris)33 std::unordered_map<std::string, std::string> TabOldPhotosClient::GetUrisByOldUris(std::vector<std::string>& uris)
34 {
35 std::unordered_map<std::string, std::string> resultMap;
36 bool cond = (uris.empty() || static_cast<std::int32_t>(uris.size()) > this->URI_MAX_SIZE);
37 CHECK_AND_RETURN_RET_LOG(!cond, resultMap, "the size is invalid, size = %{public}d",
38 static_cast<std::int32_t>(uris.size()));
39 std::string queryUri = QUERY_TAB_OLD_PHOTO;
40 Uri uri(queryUri);
41 DataShare::DataSharePredicates predicates;
42 int ret = BuildPredicates(uris, predicates);
43 CHECK_AND_RETURN_RET_LOG(ret == E_OK, resultMap, "build predicates failed");
44
45 std::vector<std::string> column;
46 column.push_back(TabOldPhotosColumn::OLD_PHOTOS_TABLE + "." + "file_id");
47 column.push_back(TabOldPhotosColumn::OLD_PHOTOS_TABLE + "." + "data");
48 column.push_back(TabOldPhotosColumn::OLD_PHOTOS_TABLE + "." + "old_file_id");
49 column.push_back(TabOldPhotosColumn::OLD_PHOTOS_TABLE + "." + "old_data");
50 column.push_back(PhotoColumn::PHOTOS_TABLE + "." + "display_name");
51 int errCode = 0;
52 std::shared_ptr<DataShare::DataShareResultSet> dataShareResultSet =
53 this->GetResultSetFromTabOldPhotos(uri, predicates, column, errCode);
54 CHECK_AND_RETURN_RET_LOG(dataShareResultSet != nullptr, resultMap, "query failed");
55 return this->GetResultMap(dataShareResultSet, uris);
56 }
57
GetResultSetFromTabOldPhotos(Uri & uri,const DataShare::DataSharePredicates & predicates,std::vector<std::string> & columns,int & errCode)58 std::shared_ptr<DataShare::DataShareResultSet> TabOldPhotosClient::GetResultSetFromTabOldPhotos(
59 Uri &uri, const DataShare::DataSharePredicates &predicates, std::vector<std::string> &columns, int &errCode)
60 {
61 std::shared_ptr<DataShare::DataShareResultSet> resultSet;
62 DataShare::DatashareBusinessError businessError;
63 sptr<IRemoteObject> token = this->mediaLibraryManager_.InitToken();
64 std::shared_ptr<DataShare::DataShareHelper> dataShareHelper =
65 DataShare::DataShareHelper::Creator(token, MEDIALIBRARY_DATA_URI);
66 CHECK_AND_RETURN_RET_LOG(dataShareHelper != nullptr, nullptr, "dataShareHelper is nullptr");
67
68 resultSet = dataShareHelper->Query(uri, predicates, columns, &businessError);
69 int count = 0;
70 CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, nullptr, "Query failed, code: %{public}d", businessError.GetCode());
71 auto ret = resultSet->GetRowCount(count);
72 CHECK_AND_RETURN_RET_LOG(ret == NativeRdb::E_OK, nullptr, "Resultset check failed, ret: %{public}d", ret);
73 return resultSet;
74 }
75
BuildPredicates(const std::vector<std::string> & queryTabOldPhotosUris,DataShare::DataSharePredicates & predicates)76 int TabOldPhotosClient::BuildPredicates(const std::vector<std::string> &queryTabOldPhotosUris,
77 DataShare::DataSharePredicates &predicates)
78 {
79 const std::string GALLERY_URI_PREFIX = "//media";
80 const std::string GALLERY_PATH = "/storage/emulated";
81
82 vector<string> clauses;
83 clauses.push_back(PhotoColumn::PHOTOS_TABLE + "." + MediaColumn::MEDIA_ID + " = " +
84 TabOldPhotosColumn::OLD_PHOTOS_TABLE + "." + TabOldPhotosColumn::MEDIA_ID);
85 predicates.InnerJoin(PhotoColumn::PHOTOS_TABLE)->On(clauses);
86
87 int conditionCount = 0;
88 for (const auto &uri : queryTabOldPhotosUris) {
89 if (uri.find(GALLERY_URI_PREFIX) != std::string::npos) {
90 size_t lastSlashPos = uri.rfind('/');
91 if (lastSlashPos != std::string::npos && lastSlashPos + 1 < uri.length()) {
92 std::string idStr = uri.substr(lastSlashPos + 1);
93 predicates.Or()->EqualTo(TabOldPhotosColumn::MEDIA_OLD_ID, idStr);
94 conditionCount += 1;
95 }
96 } else if (uri.find(GALLERY_PATH) != std::string::npos) {
97 predicates.Or()->EqualTo(TabOldPhotosColumn::MEDIA_OLD_FILE_PATH, uri);
98 conditionCount += 1;
99 } else if (!uri.empty() && std::all_of(uri.begin(), uri.end(), ::isdigit)) {
100 predicates.Or()->EqualTo(TabOldPhotosColumn::MEDIA_OLD_ID, uri);
101 conditionCount += 1;
102 }
103 }
104 CHECK_AND_RETURN_RET_LOG(conditionCount != 0, E_FAIL, "Zero uri condition");
105 return E_OK;
106 }
107
Parse(std::shared_ptr<DataShare::DataShareResultSet> & resultSet)108 std::vector<TabOldPhotosClient::TabOldPhotosClientObj> TabOldPhotosClient::Parse(
109 std::shared_ptr<DataShare::DataShareResultSet> &resultSet)
110 {
111 std::vector<TabOldPhotosClient::TabOldPhotosClientObj> result;
112 CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, result, "resultSet is null");
113 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
114 TabOldPhotosClient::TabOldPhotosClientObj obj;
115 obj.fileId = GetInt32Val(this->COLUMN_FILE_ID, resultSet);
116 obj.data = GetStringVal(this->COLUMN_DATA, resultSet);
117 obj.displayName = GetStringVal(this->COLUMN_DISPLAY_NAME, resultSet);
118 obj.oldFileId = GetInt32Val(this->COLUMN_OLD_FILE_ID, resultSet);
119 obj.oldData = GetStringVal(this->COLUMN_OLD_DATA, resultSet);
120 result.emplace_back(obj);
121 }
122 return result;
123 }
124
StoiBoundCheck(std::string toCheck)125 static bool StoiBoundCheck(std::string toCheck)
126 {
127 const std::string intMax = std::to_string(std::numeric_limits<int>::max());
128
129 return toCheck.length() < intMax.length();
130 }
131
Parse(std::vector<std::string> & queryTabOldPhotosUris)132 std::vector<TabOldPhotosClient::RequestUriObj> TabOldPhotosClient::Parse(
133 std::vector<std::string> &queryTabOldPhotosUris)
134 {
135 const std::string GALLERY_URI_PREFIX = "//media";
136 const std::string GALLERY_PATH = "/storage/emulated";
137 std::vector<TabOldPhotosClient::RequestUriObj> result;
138 for (const auto &uri : queryTabOldPhotosUris) {
139 TabOldPhotosClient::RequestUriObj obj;
140 obj.type = URI_TYPE_DEFAULT;
141 obj.requestUri = uri;
142
143 if (uri.find(GALLERY_URI_PREFIX) != std::string::npos) {
144 size_t lastSlashPos = uri.rfind('/');
145 if (lastSlashPos == std::string::npos || lastSlashPos + 1 >= uri.length()) {
146 MEDIA_ERR_LOG("Error locating media id in media uri: %{public}s", uri.c_str());
147 continue;
148 }
149 std::string idStr = uri.substr(lastSlashPos + 1);
150 if (!(!idStr.empty() && std::all_of(idStr.begin(), idStr.end(), ::isdigit)) || !StoiBoundCheck(idStr)) {
151 MEDIA_ERR_LOG("Media id is invalid in uri: %{public}s", uri.c_str());
152 continue;
153 }
154 obj.type = URI_TYPE_ID_LINK;
155 obj.oldFileId = std::stoi(idStr);
156 } else if (uri.find(GALLERY_PATH) != std::string::npos) {
157 obj.type = URI_TYPE_PATH;
158 obj.oldData = uri;
159 } else if (!uri.empty() && std::all_of(uri.begin(), uri.end(), ::isdigit) && StoiBoundCheck(uri)) {
160 int oldFileId = std::stoi(uri);
161 obj.type = URI_TYPE_ID;
162 obj.oldFileId = oldFileId;
163 }
164 if (obj.type == URI_TYPE_DEFAULT) {
165 continue;
166 }
167 result.emplace_back(obj);
168 }
169 return result;
170 }
171
BuildRequestUri(const TabOldPhotosClient::TabOldPhotosClientObj & dataObj)172 std::string TabOldPhotosClient::BuildRequestUri(const TabOldPhotosClient::TabOldPhotosClientObj &dataObj)
173 {
174 std::string filePath = dataObj.data;
175 std::string displayName = dataObj.displayName;
176 int32_t fileId = dataObj.fileId;
177 std::string baseUri = "file://media";
178 size_t lastSlashInData = filePath.rfind('/');
179 std::string fileNameInData =
180 (lastSlashInData != std::string::npos) ? filePath.substr(lastSlashInData + 1) : filePath;
181 size_t dotPos = fileNameInData.rfind('.');
182 if (dotPos != std::string::npos) {
183 fileNameInData = fileNameInData.substr(0, dotPos);
184 }
185 return baseUri + "/Photo/" + std::to_string(fileId) + "/" + fileNameInData + "/" + displayName;
186 }
187
Build(const TabOldPhotosClient::RequestUriObj & requestUriObj,const std::vector<TabOldPhotosClient::TabOldPhotosClientObj> & dataMapping)188 std::pair<std::string, std::string> TabOldPhotosClient::Build(const TabOldPhotosClient::RequestUriObj &requestUriObj,
189 const std::vector<TabOldPhotosClient::TabOldPhotosClientObj> &dataMapping)
190 {
191 if (requestUriObj.type == URI_TYPE_ID_LINK || requestUriObj.type == URI_TYPE_ID) {
192 int32_t oldFileId = requestUriObj.oldFileId;
193 auto it = std::find_if(dataMapping.begin(),
194 dataMapping.end(),
195 [oldFileId](const TabOldPhotosClient::TabOldPhotosClientObj &obj) {return obj.oldFileId == oldFileId;});
196 CHECK_AND_RETURN_RET(it == dataMapping.end(),
197 std::make_pair(requestUriObj.requestUri, this->BuildRequestUri(*it)));
198 }
199 if (requestUriObj.type == URI_TYPE_PATH) {
200 std::string oldData = requestUriObj.oldData;
201 auto it = std::find_if(dataMapping.begin(),
202 dataMapping.end(),
203 [oldData](const TabOldPhotosClient::TabOldPhotosClientObj &obj) {return obj.oldData == oldData;});
204 CHECK_AND_RETURN_RET(it == dataMapping.end(),
205 std::make_pair(requestUriObj.requestUri, this->BuildRequestUri(*it)));
206 }
207 return std::make_pair(requestUriObj.requestUri, "");
208 }
209
Parse(const std::vector<TabOldPhotosClient::TabOldPhotosClientObj> & dataMapping,std::vector<RequestUriObj> & uriList)210 std::unordered_map<std::string, std::string> TabOldPhotosClient::Parse(
211 const std::vector<TabOldPhotosClient::TabOldPhotosClientObj> &dataMapping, std::vector<RequestUriObj> &uriList)
212 {
213 std::unordered_map<std::string, std::string> resultMap;
214 for (const auto &requestUriObj : uriList) {
215 std::pair<std::string, std::string> pair = this->Build(requestUriObj, dataMapping);
216 resultMap[pair.first] = pair.second;
217 }
218 return resultMap;
219 }
220
GetResultMap(std::shared_ptr<DataShareResultSet> & resultSet,std::vector<std::string> & queryTabOldPhotosUris)221 std::unordered_map<std::string, std::string> TabOldPhotosClient::GetResultMap(
222 std::shared_ptr<DataShareResultSet> &resultSet, std::vector<std::string> &queryTabOldPhotosUris)
223 {
224 std::unordered_map<std::string, std::string> resultMap;
225 CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, resultMap, "resultSet is null");
226 std::vector<TabOldPhotosClient::TabOldPhotosClientObj> dataMapping = this->Parse(resultSet);
227 std::vector<TabOldPhotosClient::RequestUriObj> uriList = this->Parse(queryTabOldPhotosUris);
228 return this->Parse(dataMapping, uriList);
229 }
230 } // namespace OHOS::Media
231