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
16 #include "photo_accesshelper_utils.h"
17
18 #include "media_device_column.h"
19 #include "medialibrary_napi_enum_comm.h"
20
21 using namespace std;
22 using namespace OHOS::DataShare;
23 using namespace OHOS::FFI;
24
25 namespace OHOS {
26 namespace Media {
27
28 static const int32_t FIELD_IDX = 0;
29 static const int32_t VALUE_IDX = 1;
30
MallocCString(const std::string & origin)31 char *MallocCString(const std::string &origin)
32 {
33 if (origin.empty()) {
34 return nullptr;
35 }
36 auto len = origin.length() + 1;
37 char *res = static_cast<char *>(malloc(sizeof(char) * len));
38 if (res == nullptr) {
39 return nullptr;
40 }
41 return std::char_traits<char>::copy(res, origin.c_str(), len);
42 }
43
HandleSpecialDateTypePredicate(const OperationItem & item,vector<OperationItem> & operations,const FetchOptionType & fetchOptType)44 static bool HandleSpecialDateTypePredicate(const OperationItem &item,
45 vector<OperationItem> &operations, const FetchOptionType &fetchOptType)
46 {
47 vector<string>dateTypes = { MEDIA_DATA_DB_DATE_ADDED, MEDIA_DATA_DB_DATE_TRASHED, MEDIA_DATA_DB_DATE_MODIFIED,
48 MEDIA_DATA_DB_DATE_TAKEN};
49 string dateType = item.GetSingle(FIELD_IDX);
50 auto it = find(dateTypes.begin(), dateTypes.end(), dateType);
51 if (it != dateTypes.end() && item.operation != DataShare::ORDER_BY_ASC &&
52 item.operation != DataShare::ORDER_BY_DESC) {
53 dateType += "_s";
54 operations.push_back({ item.operation, { dateType, static_cast<double>(item.GetSingle(VALUE_IDX)) } });
55 return true;
56 }
57 if (DATE_TRANSITION_MAP.count(dateType) != 0) {
58 dateType = DATE_TRANSITION_MAP.at(dateType);
59 operations.push_back({ item.operation, { dateType, static_cast<double>(item.GetSingle(VALUE_IDX)) } });
60 return true;
61 }
62 return false;
63 }
64
HandleSpecialPredicate(shared_ptr<DataSharePredicates> & predicatePtr,DataSharePredicates & predicates,ExtraInfo & extraInfo)65 static bool HandleSpecialPredicate(shared_ptr<DataSharePredicates> &predicatePtr,
66 DataSharePredicates &predicates, ExtraInfo &extraInfo)
67 {
68 vector<OperationItem> operations;
69 auto &items = predicatePtr->GetOperationList();
70 for (auto &item : items) {
71 if (item.singleParams.empty()) {
72 operations.push_back(item);
73 continue;
74 }
75 if (HandleSpecialDateTypePredicate(item, operations, extraInfo.fetchOptType)) {
76 continue;
77 }
78 if (static_cast<string>(item.GetSingle(FIELD_IDX)) == DEVICE_DB_NETWORK_ID) {
79 if (item.operation != DataShare::EQUAL_TO || static_cast<string>(item.GetSingle(VALUE_IDX)).empty()) {
80 LOGE("DEVICE_DB_NETWORK_ID predicates not support %{public}d", item.operation);
81 return false;
82 }
83 extraInfo.networkId = static_cast<string>(item.GetSingle(VALUE_IDX));
84 continue;
85 } else if (static_cast<string>(item.GetSingle(FIELD_IDX)) == MEDIA_DATA_DB_URI) {
86 if (item.operation != DataShare::EQUAL_TO) {
87 LOGE("MEDIA_DATA_DB_URI predicates not support %{public}d", item.operation);
88 return false;
89 }
90 string uri = static_cast<string>(item.GetSingle(VALUE_IDX));
91 MediaFileUri::RemoveAllFragment(uri);
92 MediaFileUri fileUri(uri);
93 extraInfo.uri = uri;
94 if ((extraInfo.fetchOptType != ALBUM_FETCH_OPT) && (!fileUri.IsApi10())) {
95 fileUri = MediaFileUri(MediaFileUtils::GetRealUriFromVirtualUri(uri));
96 }
97 extraInfo.networkId = fileUri.GetNetworkId();
98 string field = (extraInfo.fetchOptType == ALBUM_FETCH_OPT) ? PhotoAlbumColumns::ALBUM_ID : MEDIA_DATA_DB_ID;
99 operations.push_back({ item.operation, { field, fileUri.GetFileId() } });
100 continue;
101 }
102 if (static_cast<string>(item.GetSingle(FIELD_IDX)) == PENDING_STATUS) {
103 continue;
104 }
105 if (LOCATION_PARAM_MAP.find(static_cast<string>(item.GetSingle(FIELD_IDX))) != LOCATION_PARAM_MAP.end()) {
106 continue;
107 }
108 operations.push_back(item);
109 }
110 predicates = DataSharePredicates(move(operations));
111 return true;
112 }
113
GetLocationPredicate(shared_ptr<DataSharePredicates> & predicatePtr,DataSharePredicates & predicates,vector<string> & fetchColumn)114 static bool GetLocationPredicate(shared_ptr<DataSharePredicates> &predicatePtr,
115 DataSharePredicates &predicates, vector<string> &fetchColumn)
116 {
117 map<string, string> locationMap;
118 auto &items = predicatePtr->GetOperationList();
119 for (auto &item : items) {
120 if (item.singleParams.empty()) {
121 continue;
122 }
123 if (LOCATION_PARAM_MAP.find(static_cast<string>(item.GetSingle(FIELD_IDX))) != LOCATION_PARAM_MAP.end()) {
124 if (item.operation != DataShare::EQUAL_TO) {
125 LOGE("location predicates not support %{public}d", item.operation);
126 return false;
127 }
128 string param = static_cast<string>(item.GetSingle(FIELD_IDX));
129 string value = static_cast<string>(item.GetSingle(VALUE_IDX));
130 locationMap.insert(make_pair(param, value));
131 if (param == DIAMETER) {
132 continue;
133 }
134 if (LOCATION_PARAM_MAP.at(param).second == DataShare::GREATER_THAN_OR_EQUAL_TO) {
135 predicates.GreaterThanOrEqualTo(LOCATION_PARAM_MAP.at(param).first, value);
136 continue;
137 }
138 if (LOCATION_PARAM_MAP.at(param).second == DataShare::LESS_THAN) {
139 predicates.LessThan(LOCATION_PARAM_MAP.at(param).first, value);
140 continue;
141 }
142 if (LOCATION_PARAM_MAP.at(param).second == DataShare::EQUAL_TO) {
143 predicates.EqualTo(LOCATION_PARAM_MAP.at(param).first, value);
144 continue;
145 }
146 }
147 }
148 if (locationMap.count(DIAMETER) == 1 && locationMap.count(START_LATITUDE) == 1
149 && locationMap.count(START_LONGITUDE) == 1) {
150 // 0.5:Used for rounding down
151 string latitudeIndex = "round((latitude - " + locationMap.at(START_LATITUDE) + ") / " +
152 locationMap.at(DIAMETER) + " - 0.5)";
153 string longitudeIndex = "round((longitude - " + locationMap.at(START_LONGITUDE) + ") / " +
154 locationMap.at(DIAMETER) + " - 0.5)";
155 string albumName = LATITUDE + "||'_'||" + LONGITUDE + "||'_'||" + latitudeIndex + "||'_'||" +
156 longitudeIndex + " AS " + ALBUM_NAME;
157 fetchColumn.push_back(albumName);
158 string locationGroup = latitudeIndex + "," + longitudeIndex;
159 predicates.GroupBy({ locationGroup });
160 }
161 return true;
162 }
163
GetPredicate(COptions options,DataSharePredicates & predicates,vector<string> & fetchColumn,ExtraInfo & extraInfo,int32_t & errCode)164 bool GetPredicate(COptions options, DataSharePredicates &predicates, vector<string> &fetchColumn,
165 ExtraInfo &extraInfo, int32_t &errCode)
166 {
167 auto native = FFIData::GetData<DataSharePredicatesImpl>(options.predicates);
168 if (native == nullptr) {
169 LOGE("get DataSharePredicatesImpl failed.");
170 errCode = JS_INNER_FAIL;
171 return false;
172 }
173 auto predicatePtr = native->GetPredicates();
174 if (predicatePtr == nullptr) {
175 LOGE("DataSharePredicates is null");
176 errCode = JS_INNER_FAIL;
177 return false;
178 }
179 if (!HandleSpecialPredicate(predicatePtr, predicates, extraInfo) ||
180 (!GetLocationPredicate(predicatePtr, predicates, fetchColumn))) {
181 LOGE("invalid predicate");
182 errCode = JS_ERR_PARAMETER_INVALID;
183 return false;
184 }
185 return true;
186 }
187
GetArrayProperty(COptions options,vector<string> & fetchColumn,int32_t & errCode)188 static bool GetArrayProperty(COptions options,
189 vector<string> &fetchColumn, int32_t &errCode)
190 {
191 if (errCode != E_SUCCESS) {
192 return false;
193 }
194 for (int64_t i = 0; i < options.fetchColumns.size; i++) {
195 fetchColumn.emplace_back(string(options.fetchColumns.head[i]));
196 }
197 return true;
198 }
199
GetFetchOption(COptions options,DataSharePredicates & predicates,vector<string> & fetchColumn,ExtraInfo & extraInfo,int32_t & errCode)200 void GetFetchOption(COptions options, DataSharePredicates &predicates,
201 vector<string> &fetchColumn, ExtraInfo &extraInfo, int32_t &errCode)
202 {
203 errCode = E_SUCCESS;
204 if (!GetPredicate(options, predicates, fetchColumn, extraInfo, errCode)) {
205 LOGE("invalid predicate");
206 return;
207 }
208 if (!GetArrayProperty(options, fetchColumn, errCode)) {
209 LOGE("Failed to parse fetchColumn");
210 return;
211 }
212 }
213
AddDefaultAssetColumns(vector<string> & fetchColumn,function<bool (const string & columnName)> isValidColumn,NapiAssetType assetType,int32_t & errCode,const PhotoAlbumSubType subType)214 void AddDefaultAssetColumns(vector<string> &fetchColumn,
215 function<bool(const string &columnName)> isValidColumn, NapiAssetType assetType,
216 int32_t &errCode, const PhotoAlbumSubType subType)
217 {
218 auto validFetchColumns = MediaColumn::DEFAULT_FETCH_COLUMNS;
219 if (assetType == TYPE_PHOTO) {
220 validFetchColumns.insert(
221 PhotoColumn::DEFAULT_FETCH_COLUMNS.begin(), PhotoColumn::DEFAULT_FETCH_COLUMNS.end());
222 }
223 switch (subType) {
224 case PhotoAlbumSubType::FAVORITE:
225 validFetchColumns.insert(MediaColumn::MEDIA_IS_FAV);
226 break;
227 case PhotoAlbumSubType::VIDEO:
228 validFetchColumns.insert(MediaColumn::MEDIA_TYPE);
229 break;
230 case PhotoAlbumSubType::HIDDEN:
231 validFetchColumns.insert(MediaColumn::MEDIA_HIDDEN);
232 break;
233 case PhotoAlbumSubType::TRASH:
234 validFetchColumns.insert(MediaColumn::MEDIA_DATE_TRASHED);
235 break;
236 case PhotoAlbumSubType::SCREENSHOT:
237 case PhotoAlbumSubType::CAMERA:
238 validFetchColumns.insert(PhotoColumn::PHOTO_SUBTYPE);
239 break;
240 default:
241 break;
242 }
243 for (const auto &column : fetchColumn) {
244 if (column == PENDING_STATUS) {
245 validFetchColumns.insert(MediaColumn::MEDIA_TIME_PENDING);
246 } else if (isValidColumn(column)) {
247 validFetchColumns.insert(column);
248 } else if (column == MEDIA_DATA_DB_URI) {
249 continue;
250 } else if (DATE_TRANSITION_MAP.count(column) != 0) {
251 validFetchColumns.insert(DATE_TRANSITION_MAP.at(column));
252 } else {
253 errCode = JS_ERR_PARAMETER_INVALID;
254 return;
255 }
256 }
257 fetchColumn.assign(validFetchColumns.begin(), validFetchColumns.end());
258 }
259 }
260 }