1 /*
2  * Copyright (C) 2023-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 <sstream>
16 
17 #include "media_file_utils.h"
18 #include "media_log.h"
19 #include "medialibrary_errno.h"
20 #include "media_file_uri.h"
21 #include "medialibrary_helper_container.h"
22 #include "medialibrary_type_const.h"
23 #include "photo_album_column.h"
24 #include "string_ex.h"
25 
26 using namespace std;
27 namespace OHOS {
28 namespace Media {
29 const size_t LEAST_PATH_LENGTH = 2;
30 const size_t BATCH_SIZE_START_AND_END = 2;
31 const std::string MEDIA_FILE_ID_DEFAULT = "-1";
32 
33 const int ASSET_IN_BUCKET_NUM_MAX = 1000;
34 const int ASSET_DIR_START_NUM = 16;
35 
SolveMediaTypeV9(MediaType mediaType)36 static std::string SolveMediaTypeV9(MediaType mediaType)
37 {
38     switch (mediaType) {
39         case MEDIA_TYPE_AUDIO:
40             return MEDIALIBRARY_TYPE_AUDIO_URI;
41         case MEDIA_TYPE_VIDEO:
42             return MEDIALIBRARY_TYPE_VIDEO_URI;
43         case MEDIA_TYPE_IMAGE:
44             return MEDIALIBRARY_TYPE_IMAGE_URI;
45         case MEDIA_TYPE_FILE:
46         default:
47             return MEDIALIBRARY_TYPE_FILE_URI;
48     }
49 }
50 
SolveMediaTypeV10(MediaType mediaType)51 static std::string SolveMediaTypeV10(MediaType mediaType)
52 {
53     switch (mediaType) {
54         case MEDIA_TYPE_AUDIO:
55             return AudioColumn::AUDIO_TYPE_URI;
56         case MEDIA_TYPE_VIDEO:
57         case MEDIA_TYPE_IMAGE:
58             return PhotoColumn::PHOTO_TYPE_URI;
59         case MEDIA_TYPE_FILE:
60         default:
61             return MEDIALIBRARY_TYPE_FILE_URI;
62     }
63 }
64 
SolveMediaType(MediaType mediaType)65 static std::string SolveMediaType(MediaType mediaType)
66 {
67     switch (mediaType) {
68         case MEDIA_TYPE_AUDIO:
69             return MEDIALIBRARY_TYPE_AUDIO_URI;
70         case MEDIA_TYPE_VIDEO:
71             return MEDIALIBRARY_TYPE_VIDEO_URI;
72         case MEDIA_TYPE_IMAGE:
73             return MEDIALIBRARY_TYPE_IMAGE_URI;
74         case MEDIA_TYPE_ALBUM:
75             return MEDIALIBRARY_TYPE_ALBUM_URI;
76         case MEDIA_TYPE_SMARTALBUM:
77             return MEDIALIBRARY_TYPE_SMART_URI;
78         case MEDIA_TYPE_FILE:
79         default:
80             return MEDIALIBRARY_TYPE_FILE_URI;
81     }
82 }
83 
ParseUri(const string & uri)84 void MediaFileUri::ParseUri(const string &uri)
85 {
86     if (MediaFileUtils::StartsWith(uri, PhotoColumn::PHOTO_URI_PREFIX)) {
87         uriType_ = API10_PHOTO_URI;
88     } else if (MediaFileUtils::StartsWith(uri, PhotoAlbumColumns::ALBUM_URI_PREFIX)) {
89         uriType_ = API10_PHOTOALBUM_URI;
90     } else if (MediaFileUtils::StartsWith(uri, AudioColumn::AUDIO_URI_PREFIX)) {
91         uriType_ = API10_AUDIO_URI;
92     } else if (MediaFileUtils::StartsWith(uri, PhotoAlbumColumns::ANALYSIS_ALBUM_URI_PREFIX)) {
93         uriType_ = API10_ANALYSISALBUM_URI;
94     } else  {
95         uriType_ = API9_URI;
96     }
97 }
98 
GetMediaTypeUri(MediaType mediaType,const int32_t & apiVersion)99 std::string MediaFileUri::GetMediaTypeUri(MediaType mediaType, const int32_t &apiVersion)
100 {
101     switch (apiVersion) {
102         case MEDIA_API_VERSION_V9:
103             return SolveMediaTypeV9(mediaType);
104         case MEDIA_API_VERSION_V10:
105             return SolveMediaTypeV10(mediaType);
106         case MEDIA_API_VERSION_DEFAULT:
107         default:
108             return SolveMediaType(mediaType);
109     }
110 }
111 
MediaFileUriConstruct(MediaType mediaType,const std::string & fileId,const std::string & networkId,const int32_t & apiVersion,const std::string & extrUri)112 std::string MediaFileUri::MediaFileUriConstruct(MediaType mediaType, const std::string &fileId,
113     const std::string &networkId, const int32_t &apiVersion, const std::string &extrUri)
114 {
115     std::string uri = ML_FILE_URI_PREFIX;
116     uri += GetMediaTypeUri(mediaType, apiVersion);
117     if (!fileId.empty()) {
118         uri += "/" + fileId;
119     }
120 
121     if (!networkId.empty()) {
122         uri += ML_URI_NETWORKID_EQUAL + networkId;
123     }
124 
125     if (apiVersion == MEDIA_API_VERSION_V10) {
126         uri += extrUri;
127         uri = MediaFileUtils::Encode(uri);
128     }
129     ParseUri(uri);
130     return uri;
131 }
132 
SetQueryMap(MediaFileUri * uri,std::unordered_map<std::string,std::string> & queryMap)133 static void SetQueryMap(MediaFileUri* uri, std::unordered_map<std::string,
134     std::string> &queryMap)
135 {
136     // file://media/image/12?networkid=xxxx&api_version=xxxx
137     std::string query = uri->GetQuery();
138     std::string pairString;
139     std::stringstream queryStream(query);
140 
141     while (getline(queryStream, pairString, '&')) {
142         size_t splitIndex = pairString.find('=');
143         if (splitIndex == std::string::npos || splitIndex == (pairString.length() - 1)) {
144             MEDIA_ERR_LOG("failed to parse query, query field is %{private}s!", pairString.c_str());
145             continue;
146         }
147         queryMap[pairString.substr(0, splitIndex)] = pairString.substr(splitIndex + 1);
148     }
149     return;
150 }
151 
CalNetworkId(MediaFileUri * uri,std::unordered_map<std::string,std::string> queryMap)152 static std::string CalNetworkId(MediaFileUri* uri, std::unordered_map<std::string,
153     std::string> queryMap)
154 {
155     std::string scheme = uri->GetScheme();
156     if (scheme == ML_FILE_SCHEME) {
157         if (queryMap.find(ML_URI_NETWORKID) != queryMap.end()) {
158             return queryMap[ML_URI_NETWORKID];
159         }
160         return "";
161     } else if (scheme == ML_DATA_SHARE_SCHEME) {
162         return uri->GetAuthority();
163     }
164     MEDIA_DEBUG_LOG("CalNetworkId scheme is invalid, scheme is %{private}s", scheme.c_str());
165     return "";
166 }
167 
GetNetworkId()168 std::string MediaFileUri::GetNetworkId()
169 {
170     if (this->networkId_ != MEDIA_FILE_URI_EMPTY) {
171         return this->networkId_;
172     }
173     SetQueryMap(this, this->queryMap_);
174     this->networkId_ = CalNetworkId(this, this->queryMap_);
175     return this->networkId_;
176 }
177 
ParsePathWithExtrPara(std::string & path)178 static void ParsePathWithExtrPara(std::string &path)
179 {
180     auto index = path.rfind('/');
181     if (index == std::string::npos) {
182         MEDIA_ERR_LOG("find split for last string failed, %{private}s", path.c_str());
183         return;
184     }
185     auto lastStr = path.substr(index + 1);
186     auto uriTempNext = path.substr(0, index);
187     index = uriTempNext.rfind('/');
188     if (index == std::string::npos) {
189         MEDIA_ERR_LOG("find split for next string failed %{private}s", uriTempNext.c_str());
190         return;
191     }
192     auto preStr = uriTempNext.substr(index + 1);
193     if (lastStr.find('.') != std::string::npos) {
194         if (!all_of(preStr.begin(), preStr.end(), ::isdigit)) {
195             path = uriTempNext.substr(0, index);
196             return;
197         }
198         preStr = uriTempNext.substr(0, index);
199         index = preStr.rfind('/');
200         if (index == std::string::npos) {
201             path = uriTempNext;
202             return;
203         }
204         path = preStr;
205     }
206 }
207 
CalFileId(MediaFileUri * uri)208 static std::string CalFileId(MediaFileUri* uri)
209 {
210     std::string path = uri->GetPath();
211     if (uri->IsApi10()) {
212         ParsePathWithExtrPara(path);
213     }
214 
215     if (path.length() < LEAST_PATH_LENGTH) {
216         MEDIA_ERR_LOG("path is too short, path is %{private}s", path.c_str());
217         return MEDIA_FILE_ID_DEFAULT;
218     }
219 
220     std::size_t index = path.rfind("/");
221     if (index == std::string::npos || index == path.length() - 1) {
222         MEDIA_ERR_LOG("failed to rfind /, path is %{private}s", path.c_str());
223         return MEDIA_FILE_ID_DEFAULT;
224     }
225 
226     std::string fileId = path.substr(index + 1);
227     if (!std::all_of(fileId.begin(), fileId.end(), ::isdigit)) {
228         MEDIA_DEBUG_LOG("fileId is not all digit, fileId is %{private}s", fileId.c_str());
229         return MEDIA_FILE_ID_DEFAULT;
230     }
231 
232     return fileId;
233 }
234 
GetFileId()235 std::string MediaFileUri::GetFileId()
236 {
237     if (this->fileId_ != MEDIA_FILE_URI_EMPTY) {
238         return this->fileId_;
239     }
240     this->fileId_ = CalFileId(this);
241     return this->fileId_;
242 }
243 
GetTableName()244 std::string MediaFileUri::GetTableName()
245 {
246     static std::map<std::string, std::string> tableNameMap = {
247         { MEDIALIBRARY_TYPE_IMAGE_URI, PhotoColumn::PHOTOS_TABLE },
248         { MEDIALIBRARY_TYPE_VIDEO_URI, PhotoColumn::PHOTOS_TABLE },
249         { MEDIALIBRARY_TYPE_AUDIO_URI, AudioColumn::AUDIOS_TABLE },
250         { MEDIALIBRARY_TYPE_FILE_URI, MEDIALIBRARY_TABLE },
251         { AudioColumn::AUDIO_TYPE_URI, AudioColumn::AUDIOS_TABLE },
252         { PhotoColumn::PHOTO_TYPE_URI, PhotoColumn::PHOTOS_TABLE }
253     };
254 
255     std::string uriString = ToString();
256     size_t questionPosition = uriString.find_first_of('?');
257     if (questionPosition != string::npos) {
258         uriString = uriString.substr(0, questionPosition);
259     }
260 
261     for (const auto &iter : tableNameMap) {
262         if (uriString.find(iter.first) != std::string::npos) {
263             return iter.second;
264         }
265     }
266     return "";
267 }
268 
GetFilePath()269 std::string MediaFileUri::GetFilePath()
270 {
271     /* get helper */
272     std::shared_ptr<DataShare::DataShareHelper> dataShareHelper =
273             MediaLibraryHelperContainer::GetInstance()->GetDataShareHelper();
274     if (dataShareHelper == nullptr) {
275         MEDIA_ERR_LOG("get data share helper err");
276         return "";
277     }
278 
279     DataShare::DatashareBusinessError error;
280     const std::string uriString = ToString();
281     std::string queryUri(UFM_QUERY_PHOTO);
282     DataShare::DataSharePredicates predicates;
283     std::vector<std::string> columns;
284     /* check api version */
285     if (uriString.find(PhotoColumn::PHOTO_TYPE_URI) != std::string::npos) {
286         predicates.EqualTo(MediaColumn::MEDIA_ID, GetFileId());
287         columns.emplace_back(MediaColumn::MEDIA_FILE_PATH);
288         MediaFileUtils::UriAppendKeyValue(queryUri, URI_PARAM_API_VERSION);
289     } else {
290         predicates.EqualTo(MEDIA_DATA_DB_ID, GetFileId());
291         columns.emplace_back(MEDIA_DATA_DB_FILE_PATH);
292     }
293     Uri uri(queryUri);
294     /* query and check */
295     auto resultSet = dataShareHelper->Query(uri, predicates, columns, &error);
296     int32_t ret = error.GetCode();
297     if (ret != 0) {
298         MEDIA_ERR_LOG("data share query err %{public}d", ret);
299         return "";
300     }
301     int32_t rowCount;
302     ret = resultSet->GetRowCount(rowCount);
303     if (ret != 0) {
304         MEDIA_ERR_LOG("result set get row count err %{public}d", ret);
305         return "";
306     }
307     if (rowCount != 1) {
308         MEDIA_ERR_LOG("more than one record");
309         return "";
310     }
311 
312     /* get val */
313     ret = resultSet->GoToNextRow();
314     if (ret != 0) {
315         MEDIA_ERR_LOG("result set go to next row err %{public}d", ret);
316         return "";
317     }
318     std::string val;
319     ret = resultSet->GetString(0, val);
320     if (ret != 0) {
321         MEDIA_ERR_LOG("result set get string err %{public}d", ret);
322         return "";
323     }
324     return val;
325 }
326 
IsValid()327 bool MediaFileUri::IsValid()
328 {
329     std::string scheme = this->GetScheme();
330     if (scheme != ML_FILE_SCHEME &&
331         scheme != ML_DATA_SHARE_SCHEME) {
332         MEDIA_ERR_LOG("scheme is invalid, uri is %{private}s", this->ToString().c_str());
333         return false;
334     }
335 
336     if (this->GetAuthority() != ML_URI_AUTHORITY &&
337         this->GetPath().find(MEDIALIBRARY_DATA_URI_IDENTIFIER) != 0) {
338         MEDIA_ERR_LOG("failed to find /media, uri is %{private}s", this->ToString().c_str());
339         return false;
340     }
341 
342     std::string fileId = this->GetFileId();
343     if (fileId == MEDIA_FILE_ID_DEFAULT) {
344         MEDIA_ERR_LOG("fileid is invaild, uri is %{private}s", this->ToString().c_str());
345         return false;
346     }
347 
348     return true;
349 }
350 
GetQueryKeys()351 std::unordered_map<std::string, std::string> &MediaFileUri::GetQueryKeys()
352 {
353     if (queryMap_.empty()) {
354         SetQueryMap(this, this->queryMap_);
355     }
356     return queryMap_;
357 }
358 
IsApi10()359 bool MediaFileUri::IsApi10()
360 {
361     if ((ToString().find(PhotoColumn::PHOTO_TYPE_URI) != std::string::npos) ||
362         (ToString().find(AudioColumn::AUDIO_TYPE_URI) != std::string::npos) ||
363         (ToString().find(PhotoColumn::HIGHTLIGHT_COVER_URI) != std::string::npos)) {
364         return true;
365     }
366     return false;
367 }
368 
GetUriType()369 int MediaFileUri::GetUriType()
370 {
371     return uriType_;
372 }
373 
GetMediaTypeFromUri(const std::string & uri)374 MediaType MediaFileUri::GetMediaTypeFromUri(const std::string &uri)
375 {
376     if (MediaFileUtils::StartsWith(uri, PhotoColumn::PHOTO_URI_PREFIX)) {
377         return MEDIA_TYPE_PHOTO;
378     } else if (MediaFileUtils::StartsWith(uri, AudioColumn::AUDIO_URI_PREFIX)) {
379         return MEDIA_TYPE_AUDIO;
380     } else if (MediaFileUtils::StartsWith(uri, PhotoAlbumColumns::ALBUM_URI_PREFIX)) {
381         return Media::MEDIA_TYPE_ALBUM;
382     } else if (MediaFileUtils::StartsWith(uri, AUDIO_URI_PREFIX)) {
383         return Media::MEDIA_TYPE_AUDIO;
384     } else if (MediaFileUtils::StartsWith(uri, VIDEO_URI_PREFIX)) {
385         return Media::MEDIA_TYPE_VIDEO;
386     } else if (MediaFileUtils::StartsWith(uri, IMAGE_URI_PREFIX)) {
387         return Media::MEDIA_TYPE_IMAGE;
388     } else if (MediaFileUtils::StartsWith(uri, ALBUM_URI_PREFIX)) {
389         return Media::MEDIA_TYPE_ALBUM;
390     } else if (MediaFileUtils::StartsWith(uri, FILE_URI_PREFIX)) {
391         return Media::MEDIA_TYPE_FILE;
392     } else if (MediaFileUtils::StartsWith(uri, HIGHLIGHT_URI_PREFIX)) {
393         return Media::MEDIA_TYPE_FILE;
394     }
395     return Media::MEDIA_TYPE_DEFAULT;
396 }
397 
RemoveAllFragment(std::string & uri)398 void MediaFileUri::RemoveAllFragment(std::string &uri)
399 {
400     size_t fragIndex = uri.find_first_of('#');
401     if (fragIndex != std::string::npos) {
402         uri = uri.substr(0, fragIndex);
403     }
404 }
405 
UriValidCheck(Uri & uri)406 static int32_t UriValidCheck(Uri &uri)
407 {
408     std::string scheme = uri.GetScheme();
409     if (scheme != ML_FILE_SCHEME && scheme != ML_DATA_SHARE_SCHEME) {
410         MEDIA_ERR_LOG("scheme is invalid, uri is %{private}s", uri.ToString().c_str());
411         return E_INVALID_URI;
412     }
413 
414     if (uri.GetAuthority() != ML_URI_AUTHORITY && uri.GetPath().find(MEDIALIBRARY_DATA_URI_IDENTIFIER) != 0) {
415         MEDIA_ERR_LOG("failed to find /media, uri is %{private}s", uri.ToString().c_str());
416         return E_INVALID_URI;
417     }
418     return E_OK;
419 }
420 
HandleOldUriPath(std::string & path)421 static inline void HandleOldUriPath(std::string &path)
422 {
423     // Handle datashare:///media and datashare:///media/file_operation case
424     if (MediaFileUtils::StartsWith(path, MEDIALIBRARY_DATA_URI_IDENTIFIER)) {
425         path = path.substr(MEDIALIBRARY_DATA_URI_IDENTIFIER.size());
426         return;
427     }
428 }
429 
RemovePrecedSlash(std::string & path)430 static inline void RemovePrecedSlash(std::string &path)
431 {
432     if (MediaFileUtils::StartsWith(path, SLASH_STR)) {
433         path = path.substr(SLASH_STR.size());
434     }
435 }
436 
GetValidPath(Uri & uri,std::string & path)437 static void GetValidPath(Uri &uri, std::string &path)
438 {
439     if (UriValidCheck(uri) < 0) {
440         path = "";
441         return;
442     }
443 
444     path = uri.GetPath();
445     HandleOldUriPath(path);
446     RemovePrecedSlash(path);
447 }
448 
GetPathFirstDentry(Uri & uri)449 std::string MediaFileUri::GetPathFirstDentry(Uri &uri)
450 {
451     std::string path;
452     GetValidPath(uri, path);
453     // Example: file:://media/photo_operation/query, return the "photo_operation" part
454     return path.substr(0, path.find_first_of('/'));
455 }
456 
GetPathSecondDentry(Uri & uri)457 std::string MediaFileUri::GetPathSecondDentry(Uri &uri)
458 {
459     std::string ret;
460     std::string firstDentry = GetPathFirstDentry(uri);
461     if (firstDentry.empty()) {
462         return ret;
463     }
464     std::string path;
465     GetValidPath(uri, path);
466     if (path.size() < firstDentry.size() + 1) {
467         return ret;
468     }
469     // Example: file:://media/photo_operation/query, return the "query" part
470     return path.substr(firstDentry.size() + 1);
471 }
472 
GetPhotoId(const std::string & uri)473 std::string MediaFileUri::GetPhotoId(const std::string &uri)
474 {
475     if (!MediaFileUtils::StartsWith(uri, PhotoColumn::PHOTO_URI_PREFIX)) {
476         return "";
477     }
478     std::string tmp = uri.substr(PhotoColumn::PHOTO_URI_PREFIX.size());
479     return tmp.substr(0, tmp.find_first_of('/'));
480 }
481 
GetTimeIdFromUri(const std::vector<std::string> & uriBatch,std::vector<std::string> & timeIdBatch)482 void MediaFileUri::GetTimeIdFromUri(const std::vector<std::string> &uriBatch, std::vector<std::string> &timeIdBatch)
483 {
484     for (size_t i = 0; i < uriBatch.size(); ++i) {
485         std::string uri = uriBatch.at(i);
486         if (uri.empty()) {
487             continue;
488         }
489         auto index = uri.rfind(ML_URI_TIME_ID);
490         if (index == std::string::npos) {
491             MEDIA_ERR_LOG("GetTimeIdFromUri find index for time_id failed: %{private}s", uri.c_str());
492             continue;
493         }
494         timeIdBatch.emplace_back(uri.substr(index + ML_URI_TIME_ID.length()));
495     }
496 }
497 
GetTimeIdFromUri(const std::vector<std::string> & uriBatch,std::vector<std::string> & timeIdBatch,int32_t & start,int32_t & count)498 void MediaFileUri::GetTimeIdFromUri(const std::vector<std::string> &uriBatch, std::vector<std::string> &timeIdBatch,
499     int32_t &start, int32_t &count)
500 {
501     if (uriBatch.size() != BATCH_SIZE_START_AND_END) {
502         return;
503     }
504     std::vector<int32_t> offset;
505     for (size_t i = 0; i < uriBatch.size(); ++i) {
506         std::string uri = uriBatch.at(i);
507         if (uri.empty()) {
508             continue;
509         }
510         auto indexStart = uri.rfind(ML_URI_TIME_ID);
511         if (indexStart == std::string::npos) {
512             MEDIA_ERR_LOG("GetTimeIdFromUri find indexStart for time_id failed: %{private}s", uri.c_str());
513             continue;
514         }
515         auto indexEnd = uri.rfind(ML_URI_OFFSET);
516         if (indexEnd == std::string::npos) {
517             MEDIA_ERR_LOG("GetTimeIdFromUri find indexEnd for time_id failed: %{private}s", uri.c_str());
518             continue;
519         }
520         uint32_t timeIdLen = indexEnd - indexStart - ML_URI_TIME_ID.length();
521         if (indexEnd <= uri.size()) {
522             timeIdBatch.emplace_back(uri.substr(indexStart + ML_URI_TIME_ID.length(), timeIdLen));
523         }
524         if (indexEnd + ML_URI_OFFSET.length() <= uri.size()) {
525             offset.emplace_back(stoi(uri.substr(indexEnd + ML_URI_OFFSET.length())));
526         }
527     }
528     if (offset.size() != BATCH_SIZE_START_AND_END) {
529         return;
530     }
531     start = offset[0];
532     count = offset[1] - offset[0] + 1;
533 }
534 
CreateAssetBucket(int32_t fileId,int32_t & bucketNum)535 int32_t MediaFileUri::CreateAssetBucket(int32_t fileId, int32_t &bucketNum)
536 {
537     if (fileId < 0) {
538         MEDIA_ERR_LOG("input fileId [%{public}d] is invalid", fileId);
539         return E_INVALID_FILEID;
540     }
541     int start = ASSET_DIR_START_NUM;
542     int divider = ASSET_DIR_START_NUM;
543     while (fileId > start * ASSET_IN_BUCKET_NUM_MAX) {
544         divider = start;
545         start *= 2; // 2: Left shift offset
546     }
547 
548     int fileIdRemainder = fileId % divider;
549     if (fileIdRemainder == 0) {
550         bucketNum = start + fileIdRemainder;
551     } else {
552         bucketNum = (start - divider) + fileIdRemainder;
553     }
554     return E_OK;
555 }
556 
GetPathFromUri(const string & uri,bool isPhoto)557 string MediaFileUri::GetPathFromUri(const string &uri, bool isPhoto)
558 {
559     size_t index = uri.rfind('/');
560     if (index == string::npos) {
561         MEDIA_ERR_LOG("index invalid %{public}s", uri.c_str());
562         return "";
563     }
564     string realTitle = uri.substr(0, index);
565     index = realTitle.rfind('/');
566     if (index == string::npos) {
567         MEDIA_ERR_LOG("invalid realTitle %{public}s", uri.c_str());
568         return "";
569     }
570     realTitle = realTitle.substr(index + 1);
571     index = realTitle.rfind('_');
572     if (index == string::npos) {
573         MEDIA_ERR_LOG("realTitle can not find _ %{public}s", uri.c_str());
574         return "";
575     }
576     string fileId = realTitle.substr(index + 1);
577     if (!all_of(fileId.begin(), fileId.end(), ::isdigit)) {
578         MEDIA_ERR_LOG("fileId invalid %{public}s", uri.c_str());
579         return "";
580     }
581     int32_t fileUniqueId = 0;
582     if (!StrToInt(fileId, fileUniqueId)) {
583         MEDIA_ERR_LOG("invalid fileuri %{private}s", uri.c_str());
584         return "";
585     }
586     int32_t bucketNum = 0;
587     CreateAssetBucket(fileUniqueId, bucketNum);
588 
589     string ext = MediaFileUtils::GetExtensionFromPath(uri);
590     if (ext.empty()) {
591         MEDIA_ERR_LOG("invalid ext %{public}s", uri.c_str());
592         return "";
593     }
594 
595     string path = ROOT_MEDIA_DIR;
596     if (isPhoto) {
597         path += PHOTO_BUCKET + "/" + to_string(bucketNum) + "/" + realTitle + "." + ext;
598     } else {
599         path += AUDIO_BUCKET + "/" + to_string(bucketNum) + "/" + realTitle + "." + ext;
600     }
601     if (!MediaFileUtils::IsFileExists(path)) {
602         MEDIA_ERR_LOG("file not exist, path=%{private}s", path.c_str());
603         return "";
604     }
605     return path;
606 }
607 } // namespace Media
608 } // namespace OHOS
609