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