• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 <sstream>
16 
17 #include "media_file_uri.h"
18 #include "media_file_utils.h"
19 #include "media_log.h"
20 #include "medialibrary_errno.h"
21 #include "medialibrary_helper_container.h"
22 #include "medialibrary_type_const.h"
23 #include "photo_album_column.h"
24 
25 using namespace std;
26 namespace OHOS {
27 namespace Media {
28 const size_t LEAST_PATH_LENGTH = 2;
29 const std::string MEDIA_FILE_ID_DEFAULT = "-1";
SolveMediaTypeV9(MediaType mediaType)30 static std::string SolveMediaTypeV9(MediaType mediaType)
31 {
32     switch (mediaType) {
33         case MEDIA_TYPE_AUDIO:
34             return MEDIALIBRARY_TYPE_AUDIO_URI;
35         case MEDIA_TYPE_VIDEO:
36             return MEDIALIBRARY_TYPE_VIDEO_URI;
37         case MEDIA_TYPE_IMAGE:
38             return MEDIALIBRARY_TYPE_IMAGE_URI;
39         case MEDIA_TYPE_FILE:
40         default:
41             return MEDIALIBRARY_TYPE_FILE_URI;
42     }
43 }
44 
SolveMediaTypeV10(MediaType mediaType)45 static std::string SolveMediaTypeV10(MediaType mediaType)
46 {
47     switch (mediaType) {
48         case MEDIA_TYPE_AUDIO:
49             return AudioColumn::AUDIO_TYPE_URI;
50         case MEDIA_TYPE_VIDEO:
51         case MEDIA_TYPE_IMAGE:
52             return PhotoColumn::PHOTO_TYPE_URI;
53         case MEDIA_TYPE_FILE:
54         default:
55             return MEDIALIBRARY_TYPE_FILE_URI;
56     }
57 }
58 
SolveMediaType(MediaType mediaType)59 static std::string SolveMediaType(MediaType mediaType)
60 {
61     switch (mediaType) {
62         case MEDIA_TYPE_AUDIO:
63             return MEDIALIBRARY_TYPE_AUDIO_URI;
64         case MEDIA_TYPE_VIDEO:
65             return MEDIALIBRARY_TYPE_VIDEO_URI;
66         case MEDIA_TYPE_IMAGE:
67             return MEDIALIBRARY_TYPE_IMAGE_URI;
68         case MEDIA_TYPE_ALBUM:
69             return MEDIALIBRARY_TYPE_ALBUM_URI;
70         case MEDIA_TYPE_SMARTALBUM:
71             return MEDIALIBRARY_TYPE_SMART_URI;
72         case MEDIA_TYPE_FILE:
73         default:
74             return MEDIALIBRARY_TYPE_FILE_URI;
75     }
76 }
77 
ParseUri(const string & uri)78 void MediaFileUri::ParseUri(const string &uri)
79 {
80     if (MediaFileUtils::StartsWith(uri, PhotoColumn::PHOTO_URI_PREFIX)) {
81         uriType_ = API10_PHOTO_URI;
82     } else if (MediaFileUtils::StartsWith(uri, PhotoAlbumColumns::ALBUM_URI_PREFIX)) {
83         uriType_ = API10_PHOTOALBUM_URI;
84     } else if (MediaFileUtils::StartsWith(uri, AudioColumn::AUDIO_URI_PREFIX)) {
85         uriType_ = API10_AUDIO_URI;
86     } else  {
87         uriType_ = API9_URI;
88     }
89 }
90 
GetMediaTypeUri(MediaType mediaType,const int32_t & apiVersion)91 std::string MediaFileUri::GetMediaTypeUri(MediaType mediaType, const int32_t &apiVersion)
92 {
93     switch (apiVersion) {
94         case MEDIA_API_VERSION_V9:
95             return SolveMediaTypeV9(mediaType);
96         case MEDIA_API_VERSION_V10:
97             return SolveMediaTypeV10(mediaType);
98         case MEDIA_API_VERSION_DEFAULT:
99         default:
100             return SolveMediaType(mediaType);
101     }
102 }
103 
MediaFileUriConstruct(MediaType mediaType,const std::string & fileId,const std::string & networkId,const int32_t & apiVersion,const std::string & extrUri)104 std::string MediaFileUri::MediaFileUriConstruct(MediaType mediaType, const std::string &fileId,
105     const std::string &networkId, const int32_t &apiVersion, const std::string &extrUri)
106 {
107     std::string uri = ML_FILE_URI_PREFIX;
108     uri += GetMediaTypeUri(mediaType, apiVersion);
109     if (!fileId.empty()) {
110         uri += "/" + fileId;
111     }
112 
113     if (!networkId.empty()) {
114         uri += ML_URI_NETWORKID_EQUAL + networkId;
115     }
116 
117     if (apiVersion == MEDIA_API_VERSION_V10) {
118         uri += extrUri;
119         uri = MediaFileUtils::Encode(uri);
120     }
121     ParseUri(uri);
122     return uri;
123 }
124 
SetQueryMap(MediaFileUri * uri,std::unordered_map<std::string,std::string> & queryMap)125 static void SetQueryMap(MediaFileUri* uri, std::unordered_map<std::string,
126     std::string> &queryMap)
127 {
128     // file://media/image/12?networkid=xxxx&api_version=xxxx
129     std::string query = uri->GetQuery();
130     std::string pairString;
131     std::stringstream queryStream(query);
132 
133     while (getline(queryStream, pairString, '&')) {
134         size_t splitIndex = pairString.find('=');
135         if (splitIndex == std::string::npos || splitIndex == (pairString.length() - 1)) {
136             MEDIA_ERR_LOG("failed to parse query, query field is %{private}s!", pairString.c_str());
137             continue;
138         }
139         queryMap[pairString.substr(0, splitIndex)] = pairString.substr(splitIndex + 1);
140     }
141     return;
142 }
143 
CalNetworkId(MediaFileUri * uri,std::unordered_map<std::string,std::string> queryMap)144 static std::string CalNetworkId(MediaFileUri* uri, std::unordered_map<std::string,
145     std::string> queryMap)
146 {
147     std::string scheme = uri->GetScheme();
148     if (scheme == ML_FILE_SCHEME) {
149         if (queryMap.find(ML_URI_NETWORKID) != queryMap.end()) {
150             return queryMap[ML_URI_NETWORKID];
151         }
152         return "";
153     } else if (scheme == ML_DATA_SHARE_SCHEME) {
154         return uri->GetAuthority();
155     }
156     MEDIA_ERR_LOG("CalNetworkId scheme is invalid, scheme is %{private}s", scheme.c_str());
157     return "";
158 }
159 
GetNetworkId()160 std::string MediaFileUri::GetNetworkId()
161 {
162     if (this->networkId_ != MEDIA_FILE_URI_EMPTY) {
163         return this->networkId_;
164     }
165     SetQueryMap(this, this->queryMap_);
166     this->networkId_ = CalNetworkId(this, this->queryMap_);
167     return this->networkId_;
168 }
169 
ParsePathWithExtrPara(std::string & path)170 static void ParsePathWithExtrPara(std::string &path)
171 {
172     auto index = path.rfind('/');
173     if (index == std::string::npos) {
174         MEDIA_ERR_LOG("find split for last string failed, %{private}s", path.c_str());
175         return;
176     }
177     auto lastStr = path.substr(index + 1);
178     auto uriTempNext = path.substr(0, index);
179     index = uriTempNext.rfind('/');
180     if (index == std::string::npos) {
181         MEDIA_ERR_LOG("find split for next string failed %{private}s", uriTempNext.c_str());
182         return;
183     }
184     auto preStr = uriTempNext.substr(index + 1);
185     if (lastStr.find('.') != std::string::npos) {
186         if (!all_of(preStr.begin(), preStr.end(), ::isdigit)) {
187             path = uriTempNext.substr(0, index);
188             return;
189         }
190         preStr = uriTempNext.substr(0, index);
191         index = preStr.rfind('/');
192         if (index == std::string::npos) {
193             path = uriTempNext;
194             return;
195         }
196         path = preStr;
197     }
198 }
199 
CalFileId(MediaFileUri * uri)200 static std::string CalFileId(MediaFileUri* uri)
201 {
202     std::string path = uri->GetPath();
203     if (uri->IsApi10()) {
204         ParsePathWithExtrPara(path);
205     }
206 
207     if (path.length() < LEAST_PATH_LENGTH) {
208         MEDIA_ERR_LOG("path is too short, path is %{private}s", path.c_str());
209         return MEDIA_FILE_ID_DEFAULT;
210     }
211 
212     std::size_t index = path.rfind("/");
213     if (index == std::string::npos || index == path.length() - 1) {
214         MEDIA_ERR_LOG("failed to rfind /, path is %{private}s", path.c_str());
215         return MEDIA_FILE_ID_DEFAULT;
216     }
217 
218     std::string fileId = path.substr(index + 1);
219     if (!std::all_of(fileId.begin(), fileId.end(), ::isdigit)) {
220         MEDIA_DEBUG_LOG("fileId is not all digit, fileId is %{private}s", fileId.c_str());
221         return MEDIA_FILE_ID_DEFAULT;
222     }
223 
224     return fileId;
225 }
226 
GetFileId()227 std::string MediaFileUri::GetFileId()
228 {
229     if (this->fileId_ != MEDIA_FILE_URI_EMPTY) {
230         return this->fileId_;
231     }
232     this->fileId_ = CalFileId(this);
233     return this->fileId_;
234 }
235 
GetTableName()236 std::string MediaFileUri::GetTableName()
237 {
238     static std::map<std::string, std::string> tableNameMap = {
239         { MEDIALIBRARY_TYPE_IMAGE_URI, PhotoColumn::PHOTOS_TABLE },
240         { MEDIALIBRARY_TYPE_VIDEO_URI, PhotoColumn::PHOTOS_TABLE },
241         { MEDIALIBRARY_TYPE_AUDIO_URI, AudioColumn::AUDIOS_TABLE },
242         { MEDIALIBRARY_TYPE_FILE_URI, MEDIALIBRARY_TABLE },
243         { AudioColumn::AUDIO_TYPE_URI, AudioColumn::AUDIOS_TABLE },
244         { PhotoColumn::PHOTO_TYPE_URI, PhotoColumn::PHOTOS_TABLE }
245     };
246 
247     std::string uriString = ToString();
248     for (const auto &iter : tableNameMap) {
249         if (uriString.find(iter.first) != std::string::npos) {
250             return iter.second;
251         }
252     }
253     return "";
254 }
255 
GetFilePath()256 std::string MediaFileUri::GetFilePath()
257 {
258     /* get helper */
259     std::shared_ptr<DataShare::DataShareHelper> dataShareHelper =
260             MediaLibraryHelperContainer::GetInstance()->GetDataShareHelper();
261     if (dataShareHelper == nullptr) {
262         MEDIA_ERR_LOG("get data share helper err");
263         return "";
264     }
265 
266     DataShare::DatashareBusinessError error;
267     const std::string uriString = ToString();
268     std::string queryUri(UFM_QUERY_PHOTO);
269     DataShare::DataSharePredicates predicates;
270     std::vector<std::string> columns;
271     /* check api version */
272     if (uriString.find(PhotoColumn::PHOTO_TYPE_URI) != std::string::npos) {
273         predicates.EqualTo(MediaColumn::MEDIA_ID, GetFileId());
274         columns.emplace_back(MediaColumn::MEDIA_FILE_PATH);
275         MediaFileUtils::UriAppendKeyValue(queryUri, URI_PARAM_API_VERSION);
276     } else {
277         predicates.EqualTo(MEDIA_DATA_DB_ID, GetFileId());
278         columns.emplace_back(MEDIA_DATA_DB_FILE_PATH);
279     }
280     Uri uri(queryUri);
281     /* query and check */
282     auto resultSet = dataShareHelper->Query(uri, predicates, columns, &error);
283     int32_t ret = error.GetCode();
284     if (ret != 0) {
285         MEDIA_ERR_LOG("data share query err %{public}d", ret);
286         return "";
287     }
288     int32_t rowCount;
289     ret = resultSet->GetRowCount(rowCount);
290     if (ret != 0) {
291         MEDIA_ERR_LOG("result set get row count err %{public}d", ret);
292         return "";
293     }
294     if (rowCount != 1) {
295         MEDIA_ERR_LOG("more than one record");
296         return "";
297     }
298 
299     /* get val */
300     ret = resultSet->GoToNextRow();
301     if (ret != 0) {
302         MEDIA_ERR_LOG("result set go to next row err %{public}d", ret);
303         return "";
304     }
305     std::string val;
306     ret = resultSet->GetString(0, val);
307     if (ret != 0) {
308         MEDIA_ERR_LOG("result set get string err %{public}d", ret);
309         return "";
310     }
311     return val;
312 }
313 
IsValid()314 bool MediaFileUri::IsValid()
315 {
316     std::string scheme = this->GetScheme();
317     if (scheme != ML_FILE_SCHEME &&
318         scheme != ML_DATA_SHARE_SCHEME) {
319         MEDIA_ERR_LOG("scheme is invalid, uri is %{private}s", this->ToString().c_str());
320         return false;
321     }
322 
323     if (this->GetAuthority() != ML_URI_AUTHORITY &&
324         this->GetPath().find(MEDIALIBRARY_DATA_URI_IDENTIFIER) != 0) {
325         MEDIA_ERR_LOG("failed to find /media, uri is %{private}s", this->ToString().c_str());
326         return false;
327     }
328 
329     std::string fileId = this->GetFileId();
330     if (fileId == MEDIA_FILE_ID_DEFAULT) {
331         MEDIA_ERR_LOG("fileid is invaild, uri is %{private}s", this->ToString().c_str());
332         return false;
333     }
334 
335     return true;
336 }
337 
GetQueryKeys()338 std::unordered_map<std::string, std::string> &MediaFileUri::GetQueryKeys()
339 {
340     if (queryMap_.empty()) {
341         SetQueryMap(this, this->queryMap_);
342     }
343     return queryMap_;
344 }
345 
IsApi10()346 bool MediaFileUri::IsApi10()
347 {
348     if ((ToString().find(PhotoColumn::PHOTO_TYPE_URI) != std::string::npos) ||
349         (ToString().find(AudioColumn::AUDIO_TYPE_URI) != std::string::npos)) {
350         return true;
351     }
352     return false;
353 }
354 
GetUriType()355 int MediaFileUri::GetUriType()
356 {
357     return uriType_;
358 }
359 
GetMediaTypeFromUri(const std::string & uri)360 MediaType MediaFileUri::GetMediaTypeFromUri(const std::string &uri)
361 {
362     if (MediaFileUtils::StartsWith(uri, PhotoColumn::PHOTO_URI_PREFIX)) {
363         return MEDIA_TYPE_PHOTO;
364     } else if (MediaFileUtils::StartsWith(uri, AudioColumn::AUDIO_URI_PREFIX)) {
365         return MEDIA_TYPE_AUDIO;
366     } else if (MediaFileUtils::StartsWith(uri, PhotoAlbumColumns::ALBUM_URI_PREFIX)) {
367         return Media::MEDIA_TYPE_ALBUM;
368     } else if (MediaFileUtils::StartsWith(uri, AUDIO_URI_PREFIX)) {
369         return Media::MEDIA_TYPE_AUDIO;
370     } else if (MediaFileUtils::StartsWith(uri, VIDEO_URI_PREFIX)) {
371         return Media::MEDIA_TYPE_VIDEO;
372     } else if (MediaFileUtils::StartsWith(uri, IMAGE_URI_PREFIX)) {
373         return Media::MEDIA_TYPE_IMAGE;
374     } else if (MediaFileUtils::StartsWith(uri, ALBUM_URI_PREFIX)) {
375         return Media::MEDIA_TYPE_ALBUM;
376     } else if (MediaFileUtils::StartsWith(uri, FILE_URI_PREFIX)) {
377         return Media::MEDIA_TYPE_FILE;
378     }
379     return Media::MEDIA_TYPE_DEFAULT;
380 }
381 
RemoveAllFragment(std::string & uri)382 void MediaFileUri::RemoveAllFragment(std::string &uri)
383 {
384     size_t fragIndex = uri.find_first_of('#');
385     if (fragIndex != std::string::npos) {
386         uri = uri.substr(0, fragIndex);
387     }
388 }
389 
UriValidCheck(Uri & uri)390 static int32_t UriValidCheck(Uri &uri)
391 {
392     std::string scheme = uri.GetScheme();
393     if (scheme != ML_FILE_SCHEME && scheme != ML_DATA_SHARE_SCHEME) {
394         MEDIA_ERR_LOG("scheme is invalid, uri is %{private}s", uri.ToString().c_str());
395         return E_INVALID_URI;
396     }
397 
398     if (uri.GetAuthority() != ML_URI_AUTHORITY && uri.GetPath().find(MEDIALIBRARY_DATA_URI_IDENTIFIER) != 0) {
399         MEDIA_ERR_LOG("failed to find /media, uri is %{private}s", uri.ToString().c_str());
400         return E_INVALID_URI;
401     }
402     return E_OK;
403 }
404 
HandleOldUriPath(std::string & path)405 static inline void HandleOldUriPath(std::string &path)
406 {
407     // Handle datashare:///media and datashare:///media/file_operation case
408     if (MediaFileUtils::StartsWith(path, MEDIALIBRARY_DATA_URI_IDENTIFIER)) {
409         path = path.substr(MEDIALIBRARY_DATA_URI_IDENTIFIER.size());
410         return;
411     }
412 }
413 
RemovePrecedSlash(std::string & path)414 static inline void RemovePrecedSlash(std::string &path)
415 {
416     if (MediaFileUtils::StartsWith(path, SLASH_STR)) {
417         path = path.substr(SLASH_STR.size());
418     }
419 }
420 
GetValidPath(Uri & uri,std::string & path)421 static void GetValidPath(Uri &uri, std::string &path)
422 {
423     if (UriValidCheck(uri) < 0) {
424         path = "";
425         return;
426     }
427 
428     path = uri.GetPath();
429     HandleOldUriPath(path);
430     RemovePrecedSlash(path);
431 }
432 
GetPathFirstDentry(Uri & uri)433 std::string MediaFileUri::GetPathFirstDentry(Uri &uri)
434 {
435     std::string path;
436     GetValidPath(uri, path);
437     // Example: file:://media/photo_operation/query, return the "photo_operation" part
438     return path.substr(0, path.find_first_of('/'));
439 }
440 
GetPathSecondDentry(Uri & uri)441 std::string MediaFileUri::GetPathSecondDentry(Uri &uri)
442 {
443     std::string ret;
444     std::string firstDentry = GetPathFirstDentry(uri);
445     if (firstDentry.empty()) {
446         return ret;
447     }
448     std::string path;
449     GetValidPath(uri, path);
450     if (path.size() < firstDentry.size() + 1) {
451         return ret;
452     }
453     // Example: file:://media/photo_operation/query, return the "query" part
454     return path.substr(firstDentry.size() + 1);
455 }
456 
GetPhotoId(const std::string & uri)457 std::string MediaFileUri::GetPhotoId(const std::string &uri)
458 {
459     if (!MediaFileUtils::StartsWith(uri, PhotoColumn::PHOTO_URI_PREFIX)) {
460         return "";
461     }
462     std::string tmp = uri.substr(PhotoColumn::PHOTO_URI_PREFIX.size());
463     return tmp.substr(0, tmp.find_first_of('/'));
464 }
465 } // namespace Media
466 } // namespace OHOS
467