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