1 /*
2 * Copyright (C) 2021 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 "media_file_utils.h"
17
18 #include <algorithm>
19
20 #include "data_ability_predicates.h"
21 #include "file_manager_service_def.h"
22 #include "file_manager_service_errno.h"
23 #include "log.h"
24 #include "media_asset.h"
25 #include "media_data_ability_const.h"
26 #include "rdb_errno.h"
27 #include "values_bucket.h"
28
29 using namespace std;
30 namespace OHOS {
31 namespace FileManagerService {
GetPathFromResult(shared_ptr<NativeRdb::AbsSharedResultSet> result,string & path)32 bool GetPathFromResult(shared_ptr<NativeRdb::AbsSharedResultSet> result, string &path)
33 {
34 int count = 0;
35 result->GetRowCount(count);
36 if (count == RESULTSET_EMPTY) {
37 ERR_LOG("AbsSharedResultSet null");
38 return false;
39 }
40 int32_t columnIndex = 0;
41 GET_COLUMN_INDEX_FROM_NAME(result, Media::MEDIA_DATA_DB_FILE_PATH, columnIndex);
42 result->GoToFirstRow();
43 int ret = result->GetString(columnIndex, path);
44 if (ret != NativeRdb::E_OK) {
45 ERR_LOG("NativeRdb gets path index fail");
46 return false;
47 }
48 GET_COLUMN_INDEX_FROM_NAME(result, Media::MEDIA_DATA_DB_RELATIVE_PATH, columnIndex);
49 string relativePath;
50 ret = result->GetString(columnIndex, relativePath);
51 if (ret != NativeRdb::E_OK) {
52 relativePath = "";
53 DEBUG_LOG("NativeRdb gets relative path is null %{public}d", columnIndex);
54 }
55 // get relative path from absolute path
56 string::size_type pos = path.find_last_of('/');
57 if (pos != string::npos) {
58 path = relativePath + path.substr(pos + 1) + "/";
59 }
60 return true;
61 }
62
IsNumber(const string & str)63 bool IsNumber(const string &str)
64 {
65 if (str.length() == 0) {
66 ERR_LOG("IsNumber input is empty ");
67 return false;
68 }
69
70 for (char const &c : str) {
71 if (isdigit(c) == 0) {
72 ERR_LOG("Index is not a number");
73 return false;
74 }
75 }
76
77 return true;
78 }
79
GetPathID(const string & uriPath,string & index)80 bool GetPathID(const string &uriPath, string &index)
81 {
82 string::size_type pos = uriPath.find_last_of('/');
83 if (pos == string::npos) {
84 ERR_LOG("invalid uri %{private}s", uriPath.c_str());
85 return false;
86 }
87 index = uriPath.substr(pos + 1);
88 if (!IsNumber(index)) {
89 ERR_LOG("invalid uri %{private}s invalid id %{public}s", uriPath.c_str(), index.c_str());
90 return false;
91 }
92 return true;
93 }
94
GetMediaType(const string & name)95 int GetMediaType(const string &name)
96 {
97 int mediaType = Media::MediaAsset::GetMediaType(name);
98 if (FILE_MIME_TYPE_MAPS.count(mediaType) == 0) {
99 ERR_LOG("invalid mediaType %{public}d", mediaType);
100 return FILE_MEDIA_TYPE;
101 }
102 return mediaType;
103 }
104
GetMimeType(const string & name)105 string GetMimeType(const string &name)
106 {
107 int mediaType = GetMediaType(name);
108 if (FILE_MIME_TYPE_MAPS.count(mediaType) == 0) {
109 ERR_LOG("invalid mediaType %{public}d", mediaType);
110 return FILE_MIME_TYPE;
111 }
112 return FILE_MIME_TYPE_MAPS.at(mediaType);
113 }
114
GetPathFromAlbumPath(const string & albumUri,string & path)115 bool GetPathFromAlbumPath(const string &albumUri, string &path)
116 {
117 string id;
118 if (!GetPathID(albumUri, id)) {
119 ERR_LOG("GetPathID fails");
120 return false;
121 }
122 string selection = Media::MEDIA_DATA_DB_ID + " LIKE ? ";
123 vector<string> selectionArgs = {id};
124 shared_ptr<NativeRdb::AbsSharedResultSet> result = MediaFileUtils::DoQuery(selection, selectionArgs);
125 if (result == nullptr) {
126 ERR_LOG("AbsSharedResultSet null");
127 return false;
128 }
129 return GetPathFromResult(result, path);
130 }
131
GetType(string type)132 string GetType(string type)
133 {
134 unordered_map<string, int> typeMap = {
135 {"image", Media::MediaType::MEDIA_TYPE_IMAGE},
136 {"video", Media::MediaType::MEDIA_TYPE_VIDEO},
137 {"audio", Media::MediaType::MEDIA_TYPE_AUDIO}
138 };
139 if (typeMap.count(type) == 0) {
140 // type is wrong
141 ERR_LOG("Type %{public}s", type.c_str());
142 return "";
143 }
144 return ToString(typeMap[type]);
145 }
146
IsFirstLevelUriPath(const string & path)147 bool IsFirstLevelUriPath(const string &path)
148 {
149 // check whether path is first level uri
150 return path == FISRT_LEVEL_ALBUM;
151 }
152
GetAlbumFromResult(shared_ptr<NativeRdb::AbsSharedResultSet> & result,vector<string> & album)153 bool GetAlbumFromResult(shared_ptr<NativeRdb::AbsSharedResultSet> &result, vector<string> &album)
154 {
155 int count = 0;
156 result->GetRowCount(count);
157 result->GoToFirstRow();
158 int32_t columnIndex;
159 GET_COLUMN_INDEX_FROM_NAME(result, Media::MEDIA_DATA_DB_RELATIVE_PATH, columnIndex);
160 for (int i = 0; i < count; i++) {
161 string path;
162 if (result->GetString(columnIndex, path) != NativeRdb::E_OK) {
163 ERR_LOG("NativeRdb gets path columnIndex fail");
164 return false;
165 }
166 path = MEDIA_ROOT_PATH + "/" + path.substr(0, path.size() - 1);
167 // add into ablum if not in album
168 if (find(album.begin(), album.end(), path) == album.end()) {
169 DEBUG_LOG(" // add into ablum path %{public}s", path.c_str());
170 album.emplace_back(path);
171 }
172 result->GoToNextRow();
173 }
174 return true;
175 }
176
FindAlbumByType(string type)177 vector<string> FindAlbumByType(string type)
178 {
179 // find out the first level Album
180 // first find out file by type
181 // then get the album
182 string selection = Media::MEDIA_DATA_DB_MEDIA_TYPE + " LIKE ?";
183 vector<string> selectionArgs = {type};
184 shared_ptr<NativeRdb::AbsSharedResultSet> result = MediaFileUtils::DoQuery(selection, selectionArgs);
185 vector<string> album;
186 if (result == nullptr) {
187 ERR_LOG("query album type returns fail");
188 return album;
189 }
190 GetAlbumFromResult(result, album);
191 return album;
192 }
193
194 /* listfile
195 * ----find "file" type
196 * --------first level view----
197 * --------selection MEDIA_DATA_DB_RELATIVE_PATH == root_path &&
198 * (MEDIA_DATA_DB_MEDIA_TYPE == "file" || MEDIA_DATA_DB_MEDIA_TYPE == "album")
199 * --------other level view ----
200 * --------selection MEDIA_DATA_DB_RELATIVE_PATH == uri.MEDIA_DATA_DB_FILE_PATH &&
201 * (MEDIA_DATA_DB_MEDIA_TYPE == "file" || MEDIA_DATA_DB_MEDIA_TYPE == "album")
202 *
203 * ----find "image"/"audio"/"video" type
204 * --------first level view----
205 * --------find out all album with type file
206 * --------selection MEDIA_DATA_DB_MEDIA_TYPE == type
207 * --------Get the relative path ----> Album path
208 * --------selection MEDIA_DATA_DB_FILE_PATH == Album path1 || selection MEDIA_DATA_DB_FILE_PATH == Album path2 || ...
209 * --------second level view ----
210 * --------selection MEDIA_DATA_DB_RELATIVE_PATH == uri.MEDIA_DATA_DB_FILE_PATH && MEDIA_DATA_DB_MEDIA_TYPE == type
211 */
CreateSelectionAndArgsFirstLevel(const string & type,string & selection,vector<string> & selectionArgs)212 int CreateSelectionAndArgsFirstLevel(const string &type, string &selection, vector<string> &selectionArgs)
213 {
214 if (type == "file") {
215 selection = Media::MEDIA_DATA_DB_RELATIVE_PATH + " LIKE ? AND (" + Media::MEDIA_DATA_DB_MEDIA_TYPE;
216 selection += " LIKE ? OR " + Media::MEDIA_DATA_DB_MEDIA_TYPE + " LIKE ? )";
217 selectionArgs = {
218 RELATIVE_ROOT_PATH, ToString(Media::MediaType::MEDIA_TYPE_FILE),
219 ToString(Media::MediaType::MEDIA_TYPE_ALBUM)
220 };
221 } else {
222 selectionArgs = FindAlbumByType(GetType(type));
223 selection = Media::MEDIA_DATA_DB_FILE_PATH + " LIKE ?";
224 if (selectionArgs.size() > 1) {
225 for (uint32_t i = 1; i < selectionArgs.size(); i++) {
226 selection += " OR " + Media::MEDIA_DATA_DB_FILE_PATH + " LIKE ?";
227 }
228 }
229 }
230 return SUCCESS;
231 }
232
CreateSelectionAndArgsOtherLevel(const string & type,const string & albumUri,string & selection,vector<string> & selectionArgs)233 int CreateSelectionAndArgsOtherLevel(const string &type, const string &albumUri, string &selection,
234 vector<string> &selectionArgs)
235 {
236 // get the album path from the album uri
237 string albumPath;
238 if (!GetPathFromAlbumPath(albumUri, albumPath)) {
239 ERR_LOG("path not exsit");
240 return E_NOEXIST;
241 }
242 if (type == "file") {
243 selection = Media::MEDIA_DATA_DB_RELATIVE_PATH + " LIKE ? AND (" + Media::MEDIA_DATA_DB_MEDIA_TYPE;
244 selection += " LIKE ? OR " + Media::MEDIA_DATA_DB_MEDIA_TYPE + " LIKE ? )";
245 selectionArgs = {
246 albumPath, ToString(Media::MediaType::MEDIA_TYPE_FILE),
247 ToString(Media::MediaType::MEDIA_TYPE_ALBUM)
248 };
249 } else {
250 selection = Media::MEDIA_DATA_DB_RELATIVE_PATH + " LIKE ? AND " + Media::MEDIA_DATA_DB_MEDIA_TYPE + " LIKE ?";
251 selectionArgs = { albumPath, GetType(type) };
252 }
253 return SUCCESS;
254 }
255
GetAlbumPath(const string & name,const string & path,string & albumPath)256 bool GetAlbumPath(const string &name, const string &path, string &albumPath)
257 {
258 if (IsFirstLevelUriPath(path)) {
259 int mediaType = GetMediaType(name);
260 albumPath = (MEDIA_TYPE_FOLDER_MAPS.count(mediaType) == 0) ? MEDIA_TYPE_FOLDER_MAPS.at(FILE_MEDIA_TYPE) :
261 MEDIA_TYPE_FOLDER_MAPS.at(mediaType);
262 return true;
263 }
264 return GetPathFromAlbumPath(path, albumPath);
265 }
266
ShowSelecArgs(const string & selection,const vector<string> & selectionArgs)267 static void ShowSelecArgs(const string &selection, const vector<string> &selectionArgs)
268 {
269 DEBUG_LOG("selection %{public}s ", selection.c_str());
270 for (auto s : selectionArgs) {
271 DEBUG_LOG("selectionArgs %{public}s", s.c_str());
272 }
273 }
274
DoListFile(const string & type,const string & path,int offset,int count,shared_ptr<NativeRdb::AbsSharedResultSet> & result)275 int MediaFileUtils::DoListFile(const string &type, const string &path, int offset, int count,
276 shared_ptr<NativeRdb::AbsSharedResultSet> &result)
277 {
278 string selection;
279 vector<string> selectionArgs;
280 if (IsFirstLevelUriPath(path)) {
281 DEBUG_LOG("IsFirstLevelUriPath");
282 CreateSelectionAndArgsFirstLevel(type, selection, selectionArgs);
283 } else {
284 int err = CreateSelectionAndArgsOtherLevel(type, path, selection, selectionArgs);
285 if (err) {
286 ERR_LOG("CreateSelectionAndArgsOtherLevel returns fail");
287 return err;
288 }
289 }
290 result = DoQuery(selection, selectionArgs, offset, count);
291 if (result == nullptr) {
292 ERR_LOG("ListFile folder is empty");
293 return E_EMPTYFOLDER;
294 }
295 return SUCCESS;
296 }
297
DoQuery(const string & selection,const vector<string> & selectionArgs)298 shared_ptr<NativeRdb::AbsSharedResultSet> MediaFileUtils::DoQuery(const string &selection,
299 const vector<string> &selectionArgs)
300 {
301 return DoQuery(selection, selectionArgs, 0, MAX_NUM);
302 }
303
DoQuery(const string & selection,const vector<string> & selectionArgs,int offset,int count)304 shared_ptr<NativeRdb::AbsSharedResultSet> MediaFileUtils::DoQuery(const string &selection,
305 const vector<string> &selectionArgs, int offset, int count)
306 {
307 ShowSelecArgs(selection, selectionArgs);
308 NativeRdb::DataAbilityPredicates predicates;
309 predicates.SetWhereClause(selection);
310 predicates.SetWhereArgs(selectionArgs);
311 predicates.SetOrder("date_taken DESC LIMIT " + ToString(offset) + "," + ToString(count));
312 DEBUG_LOG("limit %{public}d, offset %{public}d", count, offset);
313 Uri uri = Uri(Media::MEDIALIBRARY_DATA_URI);
314 vector<string> columns;
315 return abilityHelper->Query(uri, columns, predicates);
316 }
317
DoInsert(const string & name,const string & path,const string & type,string & uri)318 int MediaFileUtils::DoInsert(const string &name, const string &path, const string &type, string &uri)
319 {
320 NativeRdb::ValuesBucket values;
321 string albumPath;
322 if (!GetAlbumPath(name, path, albumPath)) {
323 ERR_LOG("path not exsit");
324 return E_NOEXIST;
325 }
326 values.PutString(Media::MEDIA_DATA_DB_RELATIVE_PATH, albumPath);
327 values.PutString(Media::MEDIA_DATA_DB_NAME, name);
328 values.PutString(Media::MEDIA_DATA_DB_MIME_TYPE, GetMimeType(name));
329 values.PutInt(Media::MEDIA_DATA_DB_MEDIA_TYPE, GetMediaType(name));
330 Uri createAsset(Media::MEDIALIBRARY_DATA_URI + "/" + Media::MEDIA_FILEOPRN + "/" +
331 Media::MEDIA_FILEOPRN_CREATEASSET);
332 int index = abilityHelper->Insert(createAsset, values);
333 if (index < 0) {
334 ERR_LOG("Fail to create fail file %{public}s uri %{private}s album %{public}s", name.c_str(),
335 path.c_str(), albumPath.c_str());
336 return E_CREATE_FAIL;
337 }
338 // use file id concatenate head as uri
339 uri = (MEDIA_TYPE_URI_MAPS.count(GetMediaType(name)) == 0) ? MEDIA_TYPE_URI_MAPS.at(FILE_MEDIA_TYPE) :
340 MEDIA_TYPE_URI_MAPS.at(GetMediaType(name));
341 uri += "/" + to_string(index);
342
343 return SUCCESS;
344 }
345
InitMediaTableColIndexMap(shared_ptr<NativeRdb::AbsSharedResultSet> result)346 bool MediaFileUtils::InitMediaTableColIndexMap(shared_ptr<NativeRdb::AbsSharedResultSet> result)
347 {
348 if (mediaTableMap.size() == 0) {
349 DEBUG_LOG("init mediaTableMap");
350 vector<pair<string, string>> mediaData = {
351 {Media::MEDIA_DATA_DB_ID, "string"},
352 {Media::MEDIA_DATA_DB_URI, "string"},
353 {Media::MEDIA_DATA_DB_MEDIA_TYPE, "string"},
354 {Media::MEDIA_DATA_DB_NAME, "string"},
355 {Media::MEDIA_DATA_DB_SIZE, "int"},
356 {Media::MEDIA_DATA_DB_DATE_ADDED, "int"},
357 {Media::MEDIA_DATA_DB_DATE_MODIFIED, "int"}
358 };
359 for (auto i : mediaData) {
360 int columnIndex = 0;
361 GET_COLUMN_INDEX_FROM_NAME(result, i.first, columnIndex);
362 mediaTableMap.emplace_back(columnIndex, i.second);
363 }
364 }
365 return true;
366 }
367
GetFileInfo(shared_ptr<NativeRdb::AbsSharedResultSet> result,shared_ptr<FileInfo> & fileInfo)368 bool MediaFileUtils::GetFileInfo(shared_ptr<NativeRdb::AbsSharedResultSet> result,
369 shared_ptr<FileInfo> &fileInfo)
370 {
371 if (!InitMediaTableColIndexMap(result)) {
372 ERR_LOG("InitMediaTableColIndexMap returns fail");
373 return false;
374 }
375 int index = 0;
376 string id;
377 result->GetString(mediaTableMap[index++].first, id);
378 string uri;
379 result->GetString(mediaTableMap[index++].first, uri);
380
381 string path = uri + "/" + id;
382 fileInfo->SetPath(path);
383 string type;
384 result->GetString(mediaTableMap[index++].first, type);
385 fileInfo->SetType(type);
386 string name;
387 result->GetString(mediaTableMap[index++].first, name);
388 fileInfo->SetName(name);
389 int64_t value;
390 result->GetLong(mediaTableMap[index++].first, value);
391 fileInfo->SetSize(value);
392 result->GetLong(mediaTableMap[index++].first, value);
393 fileInfo->SetAddedTime(value);
394 result->GetLong(mediaTableMap[index++].first, value);
395 fileInfo->SetModifiedTime(value);
396 return true;
397 }
398
GetFileInfoFromResult(shared_ptr<NativeRdb::AbsSharedResultSet> result,std::vector<shared_ptr<FileInfo>> & fileList)399 int MediaFileUtils::GetFileInfoFromResult(shared_ptr<NativeRdb::AbsSharedResultSet> result,
400 std::vector<shared_ptr<FileInfo>> &fileList)
401 {
402 int count = 0;
403 result->GetRowCount(count);
404 if (count == 0) {
405 ERR_LOG("AbsSharedResultSet null");
406 return E_EMPTYFOLDER;
407 }
408 result->GoToFirstRow();
409 for (int i = 0; i < count; i++) {
410 shared_ptr<FileInfo> fileInfo = make_shared<FileInfo>();
411 GetFileInfo(result, fileInfo);
412 fileList.push_back(fileInfo);
413 result->GoToNextRow();
414 }
415 return SUCCESS;
416 }
417
InitHelper(sptr<IRemoteObject> obj)418 bool MediaFileUtils::InitHelper(sptr<IRemoteObject> obj)
419 {
420 if (abilityHelper == nullptr) {
421 abilityHelper = AppExecFwk::DataAbilityHelper::Creator(obj, make_shared<Uri>(Media::MEDIALIBRARY_DATA_URI));
422 if (abilityHelper == nullptr) {
423 DEBUG_LOG("get %{private}s helper fail", Media::MEDIALIBRARY_DATA_URI.c_str());
424 return false;
425 }
426 }
427 return true;
428 }
429
DoGetRoot(const std::string & name,const std::string & path,std::vector<shared_ptr<FileInfo>> & fileList)430 int MediaFileUtils::DoGetRoot(const std::string &name, const std::string &path,
431 std::vector<shared_ptr<FileInfo>> &fileList)
432 {
433 shared_ptr<FileInfo> image = make_shared<FileInfo>(IMAGE_ROOT_NAME, FISRT_LEVEL_ALBUM, ALBUM_TYPE);
434 fileList.emplace_back(image);
435 shared_ptr<FileInfo> video = make_shared<FileInfo>(VIDEO_ROOT_NAME, FISRT_LEVEL_ALBUM, ALBUM_TYPE);
436 fileList.emplace_back(video);
437 shared_ptr<FileInfo> audio = make_shared<FileInfo>(AUDIO_ROOT_NAME, FISRT_LEVEL_ALBUM, ALBUM_TYPE);
438 fileList.emplace_back(audio);
439 shared_ptr<FileInfo> file = make_shared<FileInfo>(FILE_ROOT_NAME, FISRT_LEVEL_ALBUM, ALBUM_TYPE);
440 fileList.emplace_back(file);
441 return SUCCESS;
442 }
443 } // namespace FileManagerService
444 } // namespace OHOS