• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021-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 #define MLOG_TAG "FileUtils"
16 
17 #include "media_file_utils.h"
18 
19 #include <algorithm>
20 #include <dirent.h>
21 #include <fcntl.h>
22 #include <fstream>
23 #include <ftw.h>
24 #include <regex>
25 #include <sstream>
26 #include <sys/sendfile.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29 #include <unordered_map>
30 
31 #include "directory_ex.h"
32 #include "media_column.h"
33 #include "media_file_uri.h"
34 #include "media_log.h"
35 #include "medialibrary_db_const.h"
36 #include "medialibrary_errno.h"
37 #include "medialibrary_type_const.h"
38 #include "mimetype_utils.h"
39 #include "medialibrary_tracer.h"
40 #include "string_ex.h"
41 
42 using namespace std;
43 
44 namespace OHOS::Media {
45 static const mode_t CHOWN_RWX_USR_GRP = 02771;
46 static const mode_t CHOWN_RW_USR_GRP = 0660;
47 constexpr size_t DISPLAYNAME_MAX = 255;
48 const int32_t OPEN_FDS = 64;
49 const std::string PATH_PARA = "path=";
50 constexpr size_t EMPTY_DIR_ENTRY_COUNT = 2;  // Empty dir has 2 entry: . and ..
51 constexpr size_t DEFAULT_TIME_SIZE = 32;
52 
53 static const std::unordered_map<std::string, std::vector<std::string>> MEDIA_MIME_TYPE_MAP = {
54     { "application/epub+zip", { "epub" } },
55     { "application/lrc", { "lrc"} },
56     { "application/pkix-cert", { "cer" } },
57     { "application/rss+xml", { "rss" } },
58     { "application/sdp", { "sdp" } },
59     { "application/smil+xml", { "smil" } },
60     { "application/ttml+xml", { "ttml", "dfxp" } },
61     { "application/vnd.ms-pki.stl", { "stl" } },
62     { "application/vnd.ms-powerpoint", { "pot", "ppt" } },
63     { "application/vnd.ms-wpl", { "wpl" } },
64     { "application/vnd.stardivision.writer", { "vor" } },
65     { "application/vnd.youtube.yt", { "yt" } },
66     { "application/x-font", { "pcf" } },
67     { "application/x-mobipocket-ebook", { "prc", "mobi" } },
68     { "application/x-pem-file", { "pem" } },
69     { "application/x-pkcs12", { "p12", "pfx" } },
70     { "application/x-subrip", { "srt" } },
71     { "application/x-webarchive", { "webarchive" } },
72     { "application/x-webarchive-xml", { "webarchivexml" } },
73     { "application/pgp-signature", { "pgp" } },
74     { "application/x-x509-ca-cert", { "crt", "der" } },
75     { "application/json", { "json" } },
76     { "application/javascript", { "js" } },
77     { "application/zip", { "zip" } },
78     { "application/rar", { "rar" } },
79     { "application/pdf", { "pdf" } },
80     { "application/msword", { "doc" } },
81     { "application/ms-excel", { "xls" } },
82     { "application/vnd.openxmlformats-officedocument.wordprocessingml.document", { "docx" } },
83     { "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", { "xlsx" } },
84     { "application/vnd.openxmlformats-officedocument.presentationml.presentation", { "pptx" } },
85     { "audio/3gpp", { "3ga" } },
86     { "audio/ac3", { "ac3", "a52"} },
87     { "audio/amr", { "amr" } },
88     { "audio/imelody", { "imy" } },
89     { "audio/midi", { "rtttl", "xmf", "rtx" } },
90     { "audio/mobile-xmf", { "mxmf"} },
91     { "audio/mp4", { "m4a", "m4b", "m4p", "f4a", "f4b", "f4p" } },
92     { "audio/mpegurl", { "m3u" } },
93     { "audio/sp-midi", { "smf" } },
94     { "audio/x-matroska", { "mka" } },
95     { "audio/x-pn-realaudio", { "ra" } },
96     { "audio/x-mpeg", { "mp3" } },
97     { "audio/aac", { "aac", "adts", "adt" } },
98     { "audio/basic", { "snd" } },
99     { "audio/flac", { "flac" } },
100     { "audio/mpeg", { "mp3", "mp2", "mp1", "mpa", "m4r" } },
101     { "audio/wav", { "wav" } },
102     { "audio/ogg", { "ogg" } },
103     { "image/gif", { "gif"} },
104     { "image/heic", { "heic" } },
105     { "image/heic-sequence", { "heics", "heifs" } },
106     { "image/bmp", { "bmp", "bm" } },
107     { "image/heif", { "heif", "hif" } },
108     { "image/avif", { "avif" } },
109     { "image/ico", { "cur" } },
110     { "image/webp", { "webp"} },
111     { "image/x-adobe-dng", { "dng" } },
112     { "image/x-fuji-raf", { "raf" } },
113     { "image/x-icon", { "ico" } },
114     { "image/x-nikon-nrw", { "nrw" } },
115     { "image/x-panasonic-rw2", { "rw2" } },
116     { "image/x-pentax-pef", { "pef" } },
117     { "image/x-samsung-srw", { "srw" } },
118     { "image/x-sony-arw", { "arw" } },
119     { "image/jpeg", { "jpg", "jpeg", "jpe" } },
120     { "image/png", { "png" } },
121     { "image/svg+xml", { "svg" } },
122     { "image/x-dcraw", { "raw" } },
123     { "video/3gpp2", { "3gpp2", "3gp2", "3g2" } },
124     { "video/3gpp", { "3gpp", "3gp" } },
125     { "video/avi", { "avi" } },
126     { "video/mp4", { "m4v", "f4v", "mp4v", "mpeg4", "mp4" }},
127     { "video/mp2t", { "m2ts", "mts"} },
128     { "video/mp2ts", { "ts" } },
129     { "video/vnd.youtube.yt", { "vt" } },
130     { "video/x-webex", { "wrf" } },
131     { "video/mpeg", { "mpeg", "mpeg2", "mpv2", "mp2v", "m2v", "m2t", "mpeg1", "mpv1", "mp1v", "m1v", "mpg" } },
132     { "video/quicktime", { "mov" } },
133     { "video/x-matroska", { "mkv" } },
134     { "video/webm", { "webm" } },
135     { "video/H264", { "h264" } },
136     { "text/comma-separated-values", { "csv" } },
137     { "text/plain", { "diff", "po", "txt" } },
138     { "text/rtf", { "rtf" } },
139     { "text/text", { "phps", "m3u", "m3u8" } },
140     { "text/xml", { "xml" } },
141     { "text/x-vcard", { "vcf" } },
142     { "text/x-c++hdr", { "hpp", "h++", "hxx", "hh" } },
143     { "text/x-c++src", { "cpp", "c++", "cxx", "cc" } },
144     { "text/css", { "css" } },
145     { "text/html", { "html", "htm", "shtml"} },
146     { "text/markdown", { "md", "markdown" } },
147     { "text/x-java", { "java" } },
148     { "text/x-python", { "py" } }
149 };
150 
UnlinkCb(const char * fpath,const struct stat * sb,int32_t typeflag,struct FTW * ftwbuf)151 int32_t UnlinkCb(const char *fpath, const struct stat *sb, int32_t typeflag, struct FTW *ftwbuf)
152 {
153     CHECK_AND_RETURN_RET_LOG(fpath != nullptr, E_FAIL, "fpath == nullptr");
154     int32_t errRet = remove(fpath);
155     if (errRet) {
156         MEDIA_ERR_LOG("Failed to remove errno: %{public}d, path: %{private}s", errno, fpath);
157     }
158 
159     return errRet;
160 }
161 
RemoveDirectory(const string & path)162 int32_t MediaFileUtils::RemoveDirectory(const string &path)
163 {
164     return nftw(path.c_str(), UnlinkCb, OPEN_FDS, FTW_DEPTH | FTW_PHYS);
165 }
166 
Mkdir(const string & subStr,shared_ptr<int> errCodePtr)167 bool MediaFileUtils::Mkdir(const string &subStr, shared_ptr<int> errCodePtr)
168 {
169     mode_t mask = umask(0);
170     if (mkdir(subStr.c_str(), CHOWN_RWX_USR_GRP) == -1) {
171         if (errCodePtr != nullptr) {
172             *errCodePtr = errno;
173         }
174         MEDIA_ERR_LOG("Failed to create directory %{public}d", errno);
175         umask(mask);
176         return (errno == EEXIST) ? true : false;
177     }
178     umask(mask);
179     return true;
180 }
181 
CreateDirectory(const string & dirPath,shared_ptr<int> errCodePtr)182 bool MediaFileUtils::CreateDirectory(const string &dirPath, shared_ptr<int> errCodePtr)
183 {
184     string subStr;
185     string segment;
186 
187     /*  Create directory and its sub directories if does not exist
188      *  take each string after '/' create directory if does not exist.
189      *  Created directory will be the base path for the next sub directory.
190      */
191 
192     stringstream folderStream(dirPath);
193     while (getline(folderStream, segment, '/')) {
194         if (segment.empty()) {    // skip the first "/" in case of "/storage/cloud/files"
195             continue;
196         }
197 
198         subStr.append(SLASH_CHAR + segment);
199         if (!IsDirectory(subStr, errCodePtr)) {
200             if (!Mkdir(subStr, errCodePtr)) {
201                 return false;
202             }
203         }
204     }
205 
206     return true;
207 }
208 
IsFileExists(const string & fileName)209 bool MediaFileUtils::IsFileExists(const string &fileName)
210 {
211     struct stat statInfo {};
212 
213     return ((stat(fileName.c_str(), &statInfo)) == SUCCESS);
214 }
215 
IsDirEmpty(const string & path)216 bool MediaFileUtils::IsDirEmpty(const string &path)
217 {
218     DIR *dir = opendir(path.c_str());
219     if (dir == nullptr) {
220         MEDIA_ERR_LOG("Failed to open dir:%{private}s, errno: %{public}d. Just return dir NOT empty.",
221             path.c_str(), errno);
222         return false;
223     }
224     size_t entCount = 0;
225     while (readdir(dir) != nullptr) {
226         if (++entCount > EMPTY_DIR_ENTRY_COUNT) {
227             break;
228         }
229     }
230     if (closedir(dir) < 0) {
231         MEDIA_ERR_LOG("Fail to closedir: %{private}s, errno: %{public}d.", path.c_str(), errno);
232     }
233     return entCount <= EMPTY_DIR_ENTRY_COUNT;
234 }
235 
GetFileName(const string & filePath)236 string MediaFileUtils::GetFileName(const string &filePath)
237 {
238     string fileName;
239 
240     if (!(filePath.empty())) {
241         size_t lastSlash = filePath.rfind('/');
242         if (lastSlash != string::npos) {
243             if (filePath.size() > (lastSlash + 1)) {
244                 fileName = filePath.substr(lastSlash + 1);
245             }
246         }
247     }
248 
249     return fileName;
250 }
251 
IsDirectory(const string & dirName,shared_ptr<int> errCodePtr)252 bool MediaFileUtils::IsDirectory(const string &dirName, shared_ptr<int> errCodePtr)
253 {
254     struct stat statInfo {};
255 
256     if (stat(dirName.c_str(), &statInfo) == SUCCESS) {
257         if (statInfo.st_mode & S_IFDIR) {
258             return true;
259         }
260     } else if (errCodePtr != nullptr) {
261         *errCodePtr = errno;
262         return false;
263     }
264 
265     return false;
266 }
267 
CreateFile(const string & filePath)268 bool MediaFileUtils::CreateFile(const string &filePath)
269 {
270     bool errCode = false;
271 
272     if (filePath.empty() || IsFileExists(filePath)) {
273         return errCode;
274     }
275 
276     ofstream file(filePath);
277     if (!file) {
278         MEDIA_ERR_LOG("Output file path could not be created");
279         return errCode;
280     }
281 
282     if (chmod(filePath.c_str(), CHOWN_RW_USR_GRP) == SUCCESS) {
283         errCode = true;
284     }
285 
286     file.close();
287 
288     return errCode;
289 }
290 
DeleteFile(const string & fileName)291 bool MediaFileUtils::DeleteFile(const string &fileName)
292 {
293     return (remove(fileName.c_str()) == SUCCESS);
294 }
295 
DeleteDir(const string & dirName)296 bool MediaFileUtils::DeleteDir(const string &dirName)
297 {
298     bool errRet = false;
299 
300     if (IsDirectory(dirName)) {
301         errRet = (RemoveDirectory(dirName) == SUCCESS);
302     }
303 
304     return errRet;
305 }
306 
MoveFile(const string & oldPath,const string & newPath)307 bool MediaFileUtils::MoveFile(const string &oldPath, const string &newPath)
308 {
309     bool errRet = false;
310 
311     if (IsFileExists(oldPath) && !IsFileExists(newPath)) {
312         errRet = (rename(oldPath.c_str(), newPath.c_str()) == SUCCESS);
313     }
314 
315     return errRet;
316 }
317 
CopyFileUtil(const string & filePath,const string & newPath)318 bool MediaFileUtils::CopyFileUtil(const string &filePath, const string &newPath)
319 {
320     struct stat fst{};
321     bool errCode = false;
322     if (filePath.size() >= PATH_MAX) {
323         MEDIA_ERR_LOG("File path too long %{public}d", static_cast<int>(filePath.size()));
324         return errCode;
325     }
326     MEDIA_INFO_LOG("File path is %{private}s", filePath.c_str());
327     string absFilePath;
328     if (!PathToRealPath(filePath, absFilePath)) {
329         MEDIA_ERR_LOG("file is not real path, file path: %{private}s", filePath.c_str());
330         return errCode;
331     }
332     if (absFilePath.empty()) {
333         MEDIA_ERR_LOG("Failed to obtain the canonical path for source path%{private}s %{public}d",
334                       filePath.c_str(), errno);
335         return errCode;
336     }
337 
338     int32_t source = open(absFilePath.c_str(), O_RDONLY);
339     if (source == -1) {
340         MEDIA_ERR_LOG("Open failed for source file");
341         return errCode;
342     }
343 
344     int32_t dest = open(newPath.c_str(), O_WRONLY | O_CREAT, CHOWN_RWX_USR_GRP);
345     if (dest == -1) {
346         MEDIA_ERR_LOG("Open failed for destination file %{public}d", errno);
347         close(source);
348         return errCode;
349     }
350 
351     if (fstat(source, &fst) == SUCCESS) {
352         // Copy file content
353         if (sendfile(dest, source, nullptr, fst.st_size) != E_ERR) {
354             // Copy ownership and mode of source file
355             if (fchown(dest, fst.st_uid, fst.st_gid) == SUCCESS &&
356                 fchmod(dest, fst.st_mode) == SUCCESS) {
357                 errCode = true;
358             }
359         }
360     }
361 
362     close(source);
363     close(dest);
364 
365     return errCode;
366 }
367 
WriteStrToFile(const string & filePath,const string & str)368 bool MediaFileUtils::WriteStrToFile(const string &filePath, const string &str)
369 {
370     if (filePath.empty()) {
371         MEDIA_ERR_LOG("FilePath is empty");
372         return false;
373     }
374     if (str.empty()) {
375         MEDIA_ERR_LOG("Write str is empty");
376         return false;
377     }
378 
379     if (!IsFileExists(filePath)) {
380         MEDIA_ERR_LOG("Can not get FilePath %{private}s", filePath.c_str());
381         return false;
382     }
383 
384     ofstream file(filePath);
385     if (!file.is_open()) {
386         MEDIA_ERR_LOG("Can not open FilePath %{private}s", filePath.c_str());
387         return false;
388     }
389 
390     file << str;
391     file.close();
392     if (!file.good()) {
393         MEDIA_ERR_LOG("Can not write FilePath %{private}s", filePath.c_str());
394         return false;
395     }
396     return true;
397 }
398 
CopyFile(int32_t rfd,int32_t wfd)399 bool MediaFileUtils::CopyFile(int32_t rfd, int32_t wfd)
400 {
401     static const off_t sendSize1G = 1LL * 1024 * 1024 * 1024;
402     static const off_t maxSendSize2G = 2LL * 1024 * 1024 * 1024;
403     struct stat fst = {0};
404     if (fstat(rfd, &fst) != 0) {
405         MEDIA_INFO_LOG("send failed, errno=%{public}d", errno);
406         return false;
407     }
408     off_t fileSize = fst.st_size;
409 
410     if (fileSize >= maxSendSize2G) {
411         off_t offset = 0;
412         while (offset < fileSize) {
413             off_t sendSize = fileSize - offset;
414             if (sendSize > sendSize1G) {
415                 sendSize = sendSize1G;
416             }
417             if (sendfile(wfd, rfd, &offset, sendSize) != sendSize) {
418                 MEDIA_INFO_LOG("send failed, errno=%{public}d", errno);
419                 return false;
420             }
421         }
422     } else {
423         if (sendfile(wfd, rfd, nullptr, fst.st_size) != fileSize) {
424             MEDIA_INFO_LOG("send failed, errno=%{public}d", errno);
425             return false;
426         }
427     }
428     return true;
429 }
430 
RenameDir(const string & oldPath,const string & newPath)431 bool MediaFileUtils::RenameDir(const string &oldPath, const string &newPath)
432 {
433     bool errRet = false;
434 
435     if (IsDirectory(oldPath)) {
436         errRet = (rename(oldPath.c_str(), newPath.c_str()) == SUCCESS);
437         if (!errRet) {
438             MEDIA_ERR_LOG("Failed RenameDir errno %{public}d", errno);
439         }
440     }
441 
442     return errRet;
443 }
444 
CheckStringSize(const string & str,const size_t max)445 int32_t MediaFileUtils::CheckStringSize(const string &str, const size_t max)
446 {
447     size_t size = str.length();
448     if (size == 0) {
449         return -EINVAL;
450     }
451     if (size > max) {
452         return -ENAMETOOLONG;
453     }
454     return E_OK;
455 }
456 
RegexCheck(const string & str,const string & regexStr)457 static inline bool RegexCheck(const string &str, const string &regexStr)
458 {
459     const regex express(regexStr);
460     return regex_search(str, express);
461 }
462 
CheckTitle(const string & title)463 static inline int32_t CheckTitle(const string &title)
464 {
465     static const string TITLE_REGEX_CHECK = R"([\.\\/:*?"'`<>|{}\[\]])";
466     if (RegexCheck(title, TITLE_REGEX_CHECK)) {
467         MEDIA_ERR_LOG("Failed to check title regex: %{private}s", title.c_str());
468         return -EINVAL;
469     }
470     return E_OK;
471 }
472 
473 int32_t MediaFileUtils::CheckDisplayName(const string &displayName)
474 {
475     int err = CheckStringSize(displayName, DISPLAYNAME_MAX);
476     if (err < 0) {
477         return err;
478     }
479     if (displayName.at(0) == '.') {
480         return -EINVAL;
481     }
482     string title = GetTitleFromDisplayName(displayName);
483     if (title.empty()) {
484         return -EINVAL;
485     }
486     return CheckTitle(title);
487 }
488 
489 int32_t MediaFileUtils::CheckFileDisplayName(const string &displayName)
490 {
491     int err = CheckStringSize(displayName, DISPLAYNAME_MAX);
492     if (err < 0) {
493         return err;
494     }
495     if (displayName.at(0) == '.') {
496         return -EINVAL;
497     }
498     static const string TITLE_REGEX_CHECK = R"([\\/:*?"'`<>|{}\[\]])";
499     if (RegexCheck(displayName, TITLE_REGEX_CHECK)) {
500         MEDIA_ERR_LOG("Failed to check displayName regex: %{private}s", displayName.c_str());
501         return -EINVAL;
502     }
503     return E_OK;
504 }
505 
506 int32_t MediaFileUtils::CheckRelativePath(const std::string &relativePath)
507 {
508     if (relativePath.empty()) {
509         return -EINVAL;
510     }
511 
512     int firstPoint = (relativePath.front() == '/') ? 1 : 0;
513     size_t lastPoint = 0;
514     while (true) {
515         lastPoint = relativePath.find_first_of('/', firstPoint);
516         if (lastPoint == string::npos) {
517             lastPoint = relativePath.length();
518         }
519         int len = lastPoint - firstPoint;
520         if (len == 0) {
521             MEDIA_ERR_LOG("relativePath %{private}s is invalid", relativePath.c_str());
522             return -EINVAL;
523         }
524         string checkedDirName = relativePath.substr(firstPoint, len);
525         if (CheckDentryName(checkedDirName) != E_OK) {
526             MEDIA_ERR_LOG("Dir Name %{private}s is invalid in path %{private}s",
527                 checkedDirName.c_str(), relativePath.c_str());
528             return -EINVAL;
529         }
530         if (lastPoint == relativePath.length()) {
531             break;
532         }
533         firstPoint = lastPoint + 1;
534         if (firstPoint == relativePath.length()) {
535             break;
536         }
537     }
538     return E_OK;
539 }
540 
541 bool MediaFileUtils::CheckDisplayLevel(const int32_t &displayLevel)
542 {
543     if (PORTRAIT_PAGE_MODE.find(displayLevel) == PORTRAIT_PAGE_MODE.end()) {
544         MEDIA_ERR_LOG("display level %{private}d is invalid", displayLevel);
545         return false;
546     }
547     return true;
548 }
549 
550 void MediaFileUtils::FormatRelativePath(string &relativePath)
551 {
552     if (relativePath.empty()) {
553         return;
554     }
555     string FormatRelativePath = relativePath;
556     if (relativePath.back() != '/') {
557         relativePath += '/';
558     }
559     if (relativePath.front() == '/') {
560         relativePath = relativePath.substr(1);
561     }
562 }
563 
564 void MediaFileUtils::GetRootDirFromRelativePath(const string &relativePath, string &rootDir)
565 {
566     rootDir = relativePath;
567     if (relativePath.empty()) {
568         return;
569     }
570     if (relativePath.back() != '/') {
571         rootDir += '/';
572     }
573     if (rootDir[0] == '/') {
574         size_t dirIndex = rootDir.find_first_of('/', 1);
575         if (dirIndex == string::npos) {
576             return;
577         }
578         rootDir = rootDir.substr(1, dirIndex);
579     } else {
580         size_t dirIndex = rootDir.find_first_of('/');
581         if (dirIndex == string::npos) {
582             return;
583         }
584         rootDir = rootDir.substr(0, dirIndex + 1);
585     }
586 }
587 
588 int32_t MediaFileUtils::CheckAlbumName(const string &albumName)
589 {
590     int err = CheckStringSize(albumName, DISPLAYNAME_MAX);
591     if (err < 0) {
592         return err;
593     }
594 
595     static const string ALBUM_NAME_REGEX = R"([\.\\/:*?"'`<>|{}\[\]])";
596     if (RegexCheck(albumName, ALBUM_NAME_REGEX)) {
597         MEDIA_ERR_LOG("Failed to check album name regex: %{private}s", albumName.c_str());
598         return -EINVAL;
599     }
600     return E_OK;
601 }
602 
CheckDentryName(const string & dentryName)603 int32_t MediaFileUtils::CheckDentryName(const string &dentryName)
604 {
605     int err = CheckStringSize(dentryName, DISPLAYNAME_MAX);
606     if (err < 0) {
607         return err;
608     }
609 
610     static const string DENTRY_REGEX_CHECK = R"([\\/:*?"'`<>|{}\[\]])";
611     if (RegexCheck(dentryName, DENTRY_REGEX_CHECK)) {
612         MEDIA_ERR_LOG("Failed to check dentry regex: %{private}s", dentryName.c_str());
613         return -EINVAL;
614     }
615     return E_OK;
616 }
617 
618 string MediaFileUtils::GetParentPath(const string &path)
619 {
620     string name;
621     size_t slashIndex = path.rfind("/");
622     if (slashIndex != string::npos) {
623         name = path.substr(0, slashIndex);
624     }
625 
626     return name;
627 }
628 
629 string MediaFileUtils::GetTitleFromDisplayName(const string &displayName)
630 {
631     string title;
632     if (!displayName.empty()) {
633         string::size_type pos = displayName.find_last_of('.');
634         if (pos == string::npos) {
635             return "";
636         }
637         title = displayName.substr(0, pos);
638     }
639     return title;
640 }
641 
642 int64_t MediaFileUtils::GetAlbumDateModified(const string &albumPath)
643 {
644     struct stat statInfo {};
645     if (!albumPath.empty() && stat(albumPath.c_str(), &statInfo) == 0) {
646         return (statInfo.st_mtime);
647     }
648     return 0;
649 }
650 
651 int64_t MediaFileUtils::UTCTimeSeconds()
652 {
653     struct timespec t{};
654     t.tv_sec = 0;
655     t.tv_nsec = 0;
656     clock_gettime(CLOCK_REALTIME, &t);
657     return (int64_t)(t.tv_sec);
658 }
659 
660 int64_t MediaFileUtils::UTCTimeMilliSeconds()
661 {
662     struct timespec t;
663     constexpr int64_t SEC_TO_MSEC = 1e3;
664     constexpr int64_t MSEC_TO_NSEC = 1e6;
665     clock_gettime(CLOCK_REALTIME, &t);
666     return t.tv_sec * SEC_TO_MSEC + t.tv_nsec / MSEC_TO_NSEC;
667 }
668 
669 int64_t MediaFileUtils::UTCTimeNanoSeconds()
670 {
671     struct timespec t {};
672     constexpr int64_t SEC_TO_NSEC = 1e9;
673     clock_gettime(CLOCK_REALTIME, &t);
674     return t.tv_sec * SEC_TO_NSEC + t.tv_nsec;
675 }
676 
677 string MediaFileUtils::StrCreateTime(const string &format, int64_t time)
678 {
679     char strTime[DEFAULT_TIME_SIZE] = "";
680     auto tm = localtime(&time);
681     (void)strftime(strTime, sizeof(strTime), format.c_str(), tm);
682     return strTime;
683 }
684 
685 string MediaFileUtils::StrCreateTimeByMilliseconds(const string &format, int64_t time)
686 {
687     char strTime[DEFAULT_TIME_SIZE] = "";
688     int64_t times = time / MSEC_TO_SEC;
689     auto tm = localtime(&times);
690     (void)strftime(strTime, sizeof(strTime), format.c_str(), tm);
691     return strTime;
692 }
693 
694 string MediaFileUtils::GetIdFromUri(const string &uri)
695 {
696     return MediaFileUri(uri).GetFileId();
697 }
698 
699 string MediaFileUtils::GetNetworkIdFromUri(const string &uri)
700 {
701     return MediaFileUri(uri).GetNetworkId();
702 }
703 
704 string MediaFileUtils::UpdatePath(const string &path, const string &uri)
705 {
706     MediaLibraryTracer tracer;
707     tracer.Start("MediaFileUtils::UpdatePath");
708 
709     string retStr = path;
710     MEDIA_INFO_LOG("MediaFileUtils::UpdatePath path = %{private}s, uri = %{private}s", path.c_str(), uri.c_str());
711     if (path.empty() || uri.empty()) {
712         return retStr;
713     }
714 
715     string networkId = GetNetworkIdFromUri(uri);
716     if (networkId.empty()) {
717         MEDIA_INFO_LOG("MediaFileUtils::UpdatePath retStr = %{private}s", retStr.c_str());
718         return retStr;
719     }
720 
721     size_t pos = path.find(MEDIA_DATA_DEVICE_PATH);
722     if (pos == string::npos) {
723         return retStr;
724     }
725 
726     string beginStr = path.substr(0, pos);
727     if (beginStr.empty()) {
728         return retStr;
729     }
730 
731     string endStr = path.substr(pos + MEDIA_DATA_DEVICE_PATH.length());
732     if (endStr.empty()) {
733         return retStr;
734     }
735 
736     retStr = beginStr + networkId + endStr;
737     MEDIA_INFO_LOG("MediaFileUtils::UpdatePath retStr = %{private}s", retStr.c_str());
738     return retStr;
739 }
740 
741 MediaType MediaFileUtils::GetMediaType(const string &filePath)
742 {
743     if (filePath.empty()) {
744         return MEDIA_TYPE_ALL;
745     }
746 
747     string extention = GetExtensionFromPath(filePath);
748     string mimeType = MimeTypeUtils::GetMimeTypeFromExtension(extention, MEDIA_MIME_TYPE_MAP);
749     return MimeTypeUtils::GetMediaTypeFromMimeType(mimeType);
750 }
751 
752 string MediaFileUtils::SplitByChar(const string &str, const char split)
753 {
754     size_t splitIndex = str.find_last_of(split);
755     return (splitIndex == string::npos) ? ("") : (str.substr(splitIndex + 1));
756 }
757 
758 string MediaFileUtils::GetExtensionFromPath(const string &path)
759 {
760     string extention = SplitByChar(path, '.');
761     if (!extention.empty()) {
762         transform(extention.begin(), extention.end(), extention.begin(), ::tolower);
763     }
764     return extention;
765 }
766 
767 int32_t MediaFileUtils::OpenFile(const string &filePath, const string &mode)
768 {
769     int32_t errCode = E_ERR;
770 
771     if (filePath.empty() || mode.empty()) {
772         MEDIA_ERR_LOG("Invalid open argument! mode: %{private}s, path: %{private}s", mode.c_str(), filePath.c_str());
773         return errCode;
774     }
775 
776     static const unordered_map<string, int32_t> MEDIA_OPEN_MODE_MAP = {
777         { MEDIA_FILEMODE_READONLY, O_RDONLY },
778         { MEDIA_FILEMODE_WRITEONLY, O_WRONLY },
779         { MEDIA_FILEMODE_READWRITE, O_RDWR },
780         { MEDIA_FILEMODE_WRITETRUNCATE, O_WRONLY | O_TRUNC },
781         { MEDIA_FILEMODE_WRITEAPPEND, O_WRONLY | O_APPEND },
782         { MEDIA_FILEMODE_READWRITETRUNCATE, O_RDWR | O_TRUNC },
783         { MEDIA_FILEMODE_READWRITEAPPEND, O_RDWR | O_APPEND },
784     };
785     if (MEDIA_OPEN_MODE_MAP.find(mode) == MEDIA_OPEN_MODE_MAP.end()) {
786         return E_ERR;
787     }
788 
789     if (filePath.size() >= PATH_MAX) {
790         MEDIA_ERR_LOG("File path too long %{public}d", (int)filePath.size());
791         return errCode;
792     }
793     string absFilePath;
794     if (!PathToRealPath(filePath, absFilePath)) {
795         MEDIA_ERR_LOG("file is not real path, file path: %{private}s", filePath.c_str());
796         return errCode;
797     }
798     if (absFilePath.empty()) {
799         MEDIA_ERR_LOG("Failed to obtain the canonical path for source path %{public}d %{private}s",
800                       errno, filePath.c_str());
801         return errCode;
802     }
803     MEDIA_INFO_LOG("File absFilePath is %{private}s", absFilePath.c_str());
804     return open(absFilePath.c_str(), MEDIA_OPEN_MODE_MAP.at(mode));
805 }
806 
807 int32_t MediaFileUtils::CreateAsset(const string &filePath)
808 {
809     MediaLibraryTracer tracer;
810     tracer.Start("MediaFileUtils::CreateAsset");
811 
812     int32_t errCode = E_ERR;
813 
814     if (filePath.empty()) {
815         MEDIA_ERR_LOG("Filepath is empty");
816         return E_VIOLATION_PARAMETERS;
817     }
818 
819     if (IsFileExists(filePath)) {
820         MEDIA_ERR_LOG("the file exists path: %{private}s", filePath.c_str());
821         return E_FILE_EXIST;
822     }
823 
824     size_t slashIndex = filePath.rfind('/');
825     if (slashIndex != string::npos) {
826         string fileName = filePath.substr(slashIndex + 1);
827         if (!fileName.empty() && fileName.at(0) != '.') {
828             size_t dotIndex = filePath.rfind('.');
829             if ((dotIndex == string::npos) && (GetMediaType(filePath) != MEDIA_TYPE_FILE)) {
830                 return errCode;
831             }
832         }
833     }
834 
835     ofstream file(filePath);
836     if (!file) {
837         MEDIA_ERR_LOG("Output file path could not be created errno %{public}d", errno);
838         return errCode;
839     }
840 
841     file.close();
842 
843     return E_SUCCESS;
844 }
845 
846 int32_t MediaFileUtils::ModifyAsset(const string &oldPath, const string &newPath)
847 {
848     int32_t err = E_MODIFY_DATA_FAIL;
849 
850     if (oldPath.empty() || newPath.empty()) {
851         MEDIA_ERR_LOG("Failed to modify asset, oldPath: %{private}s or newPath: %{private}s is empty!",
852             oldPath.c_str(), newPath.c_str());
853         return err;
854     }
855     if (!IsFileExists(oldPath)) {
856         MEDIA_ERR_LOG("Failed to modify asset, oldPath: %{private}s does not exist!", oldPath.c_str());
857         return E_NO_SUCH_FILE;
858     }
859     if (IsFileExists(newPath)) {
860         MEDIA_ERR_LOG("Failed to modify asset, newPath: %{private}s is already exist!", newPath.c_str());
861         return E_FILE_EXIST;
862     }
863     err = rename(oldPath.c_str(), newPath.c_str());
864     if (err < 0) {
865         MEDIA_ERR_LOG("Failed rename old: %{public}s : %{public}d, new: %{public}s : %{public}d errno %{public}d",
866             oldPath.c_str(), IsFileExists(oldPath), newPath.c_str(), IsFileExists(newPath), errno);
867         return E_FILE_OPER_FAIL;
868     }
869 
870     return E_SUCCESS;
871 }
872 
873 int32_t MediaFileUtils::OpenAsset(const string &filePath, const string &mode)
874 {
875     if (filePath.empty()) {
876         return E_INVALID_PATH;
877     }
878     if (mode.empty()) {
879         return E_INVALID_MODE;
880     }
881 
882     int32_t flags = O_RDWR;
883     if (mode == MEDIA_FILEMODE_READONLY) {
884         flags = O_RDONLY;
885     } else if (mode == MEDIA_FILEMODE_WRITEONLY) {
886         flags = O_WRONLY;
887     } else if (mode == MEDIA_FILEMODE_WRITETRUNCATE) {
888         flags = O_WRONLY | O_TRUNC;
889     } else if (mode == MEDIA_FILEMODE_WRITEAPPEND) {
890         flags = O_WRONLY | O_APPEND;
891     } else if (mode == MEDIA_FILEMODE_READWRITETRUNCATE) {
892         flags = O_RDWR | O_TRUNC;
893     }
894 
895     if (filePath.size() >= PATH_MAX) {
896         MEDIA_ERR_LOG("File path too long %{public}d", (int)filePath.size());
897         return E_INVALID_PATH;
898     }
899     MEDIA_INFO_LOG("File path is %{private}s", filePath.c_str());
900     std::string absFilePath;
901     if (!PathToRealPath(filePath, absFilePath)) {
902         MEDIA_ERR_LOG("file is not real path, file path: %{private}s", filePath.c_str());
903         return E_INVALID_PATH;
904     }
905     if (absFilePath.empty()) {
906         MEDIA_ERR_LOG("Failed to obtain the canonical path for source path %{private}s %{public}d",
907                       filePath.c_str(), errno);
908         return E_INVALID_PATH;
909     }
910 
911     MEDIA_INFO_LOG("File absFilePath is %{private}s", absFilePath.c_str());
912     return open(absFilePath.c_str(), flags);
913 }
914 
915 int32_t MediaFileUtils::CloseAsset(int32_t fd)
916 {
917     return close(fd);
918 }
919 
920 std::string MediaFileUtils::GetMediaTypeUri(MediaType mediaType)
921 {
922     switch (mediaType) {
923         case MEDIA_TYPE_AUDIO:
924             return MEDIALIBRARY_AUDIO_URI;
925         case MEDIA_TYPE_VIDEO:
926             return MEDIALIBRARY_VIDEO_URI;
927         case MEDIA_TYPE_IMAGE:
928             return MEDIALIBRARY_IMAGE_URI;
929         case MEDIA_TYPE_SMARTALBUM:
930             return MEDIALIBRARY_SMARTALBUM_CHANGE_URI;
931         case MEDIA_TYPE_DEVICE:
932             return MEDIALIBRARY_DEVICE_URI;
933         case MEDIA_TYPE_FILE:
934         default:
935             return MEDIALIBRARY_FILE_URI;
936     }
937 }
938 
939 std::string MediaFileUtils::GetMediaTypeUriV10(MediaType mediaType)
940 {
941     switch (mediaType) {
942         case MEDIA_TYPE_AUDIO:
943             return AudioColumn::DEFAULT_AUDIO_URI;
944         case MEDIA_TYPE_VIDEO:
945         case MEDIA_TYPE_IMAGE:
946             return PhotoColumn::DEFAULT_PHOTO_URI;
947         case MEDIA_TYPE_SMARTALBUM:
948             return MEDIALIBRARY_SMARTALBUM_CHANGE_URI;
949         case MEDIA_TYPE_DEVICE:
950             return MEDIALIBRARY_DEVICE_URI;
951         case MEDIA_TYPE_FILE:
952         default:
953             return MEDIALIBRARY_FILE_URI;
954     }
955 }
956 
957 bool MediaFileUtils::CheckMode(const string &mode)
958 {
959     if (mode.empty()) {
960         return false;
961     }
962     if (MEDIA_OPEN_MODES.find(mode) != MEDIA_OPEN_MODES.end()) {
963         return true;
964     } else {
965         MEDIA_ERR_LOG("Input Mode %{private}s is invalid", mode.c_str());
966         return false;
967     }
968 }
969 
970 size_t MediaFileUtils::FindIgnoreCase(const std::string &str, const std::string &key)
971 {
972     auto it = search(str.begin(), str.end(), key.begin(), key.end(), [](const char a, const char b) {
973         return ::tolower(a) == ::tolower(b);
974     });
975     if (it == str.end()) {
976         return string::npos;
977     }
978     size_t pos = it - str.begin();
979     return (pos > 0) ? pos : 0;
980 }
981 
982 int64_t MediaFileUtils::GetVirtualIdByType(int32_t id, MediaType type)
983 {
984     switch (type) {
985         case MediaType::MEDIA_TYPE_IMAGE:
986         case MediaType::MEDIA_TYPE_VIDEO: {
987             return (int64_t) id * VIRTUAL_ID_DIVIDER - PHOTO_VIRTUAL_IDENTIFIER;
988         }
989         case MediaType::MEDIA_TYPE_AUDIO: {
990             return (int64_t) id * VIRTUAL_ID_DIVIDER - AUDIO_VIRTUAL_IDENTIFIER;
991         }
992         default: {
993             return (int64_t)id * VIRTUAL_ID_DIVIDER - FILE_VIRTUAL_IDENTIFIER;
994         }
995     }
996 }
997 
998 double MediaFileUtils::GetRealIdByTable(int32_t virtualId, const string &tableName)
999 {
1000     if (tableName == PhotoColumn::PHOTOS_TABLE) {
1001         return (double) (virtualId + PHOTO_VIRTUAL_IDENTIFIER) / VIRTUAL_ID_DIVIDER;
1002     } else if (tableName == AudioColumn::AUDIOS_TABLE) {
1003         return (double) (virtualId + AUDIO_VIRTUAL_IDENTIFIER) / VIRTUAL_ID_DIVIDER;
1004     } else {
1005         return (double) (virtualId + FILE_VIRTUAL_IDENTIFIER) / VIRTUAL_ID_DIVIDER;
1006     }
1007 }
1008 
1009 string MediaFileUtils::GetVirtualUriFromRealUri(const string &uri, const string &extrUri)
1010 {
1011     if ((uri.find(PhotoColumn::PHOTO_TYPE_URI) != string::npos) ||
1012        (uri.find(AudioColumn::AUDIO_TYPE_URI) != string::npos)) {
1013         return uri;
1014     }
1015 
1016     string pureUri = uri;
1017     string suffixUri;
1018     size_t questionMaskPoint = uri.rfind('?');
1019     size_t hashKeyPoint = uri.rfind('#');
1020     if (questionMaskPoint != string::npos) {
1021         suffixUri = uri.substr(questionMaskPoint);
1022         pureUri = uri.substr(0, questionMaskPoint);
1023     } else if (hashKeyPoint != string::npos) {
1024         suffixUri = uri.substr(hashKeyPoint);
1025         pureUri = uri.substr(0, hashKeyPoint);
1026     }
1027 
1028     MediaFileUri fileUri(pureUri);
1029     string fileId = fileUri.GetFileId();
1030     if (!all_of(fileId.begin(), fileId.end(), ::isdigit)) {
1031         return uri;
1032     }
1033     int32_t id;
1034     if (!StrToInt(fileId, id)) {
1035         MEDIA_ERR_LOG("invalid fileuri %{private}s", uri.c_str());
1036         return uri;
1037     }
1038     int64_t virtualId;
1039     MediaType type;
1040     if ((pureUri.find(MEDIALIBRARY_TYPE_IMAGE_URI) != string::npos)) {
1041         type = MediaType::MEDIA_TYPE_IMAGE;
1042         virtualId = GetVirtualIdByType(id, MediaType::MEDIA_TYPE_IMAGE);
1043     } else if (pureUri.find(MEDIALIBRARY_TYPE_VIDEO_URI) != string::npos) {
1044         type = MediaType::MEDIA_TYPE_VIDEO;
1045         virtualId = GetVirtualIdByType(id, MediaType::MEDIA_TYPE_VIDEO);
1046     } else if ((pureUri.find(MEDIALIBRARY_TYPE_AUDIO_URI) != string::npos)) {
1047         type = MediaType::MEDIA_TYPE_AUDIO;
1048         virtualId = GetVirtualIdByType(id, MediaType::MEDIA_TYPE_AUDIO);
1049     } else {
1050         type = MediaType::MEDIA_TYPE_FILE;
1051         virtualId = GetVirtualIdByType(id, MediaType::MEDIA_TYPE_FILE);
1052     }
1053     MediaFileUri virtualUri(type, to_string(virtualId), fileUri.GetNetworkId(),
1054         (fileUri.IsApi10() ? MEDIA_API_VERSION_V10 : MEDIA_API_VERSION_V9),
1055         (fileUri.IsApi10() ? extrUri : ""));
1056 
1057     if (suffixUri.empty()) {
1058         return virtualUri.ToString();
1059     } else {
1060         return virtualUri.ToString() + suffixUri;
1061     }
1062 }
1063 
1064 void GetExtrParamFromUri(const std::string &uri, std::string &displayName)
1065 {
1066     if (uri.find(PATH_PARA) != string::npos) {
1067         size_t lastSlashPosition = uri.rfind('/');
1068         if (lastSlashPosition != string::npos) {
1069             displayName = uri.substr(lastSlashPosition + 1);
1070         }
1071     }
1072 }
1073 
1074 void InitPureAndSuffixUri(string &pureUri, string &suffixUri, const string &uri)
1075 {
1076     size_t questionMaskPoint = uri.rfind('?');
1077     size_t hashKeyPoint = uri.rfind('#');
1078     if (questionMaskPoint != string::npos) {
1079         suffixUri = uri.substr(questionMaskPoint);
1080         pureUri = uri.substr(0, questionMaskPoint);
1081     } else if (hashKeyPoint != string::npos) {
1082         suffixUri = uri.substr(hashKeyPoint);
1083         pureUri = uri.substr(0, hashKeyPoint);
1084     }
1085 }
1086 
1087 string MediaFileUtils::GetRealUriFromVirtualUri(const string &uri)
1088 {
1089     if ((uri.find(PhotoColumn::PHOTO_TYPE_URI) != string::npos) ||
1090        (uri.find(AudioColumn::AUDIO_TYPE_URI) != string::npos)) {
1091         return uri;
1092     }
1093 
1094     string pureUri = uri;
1095     string suffixUri;
1096     InitPureAndSuffixUri(pureUri, suffixUri, uri);
1097     MediaFileUri fileUri(pureUri);
1098     string fileId = fileUri.GetFileId();
1099     if (!all_of(fileId.begin(), fileId.end(), ::isdigit)) {
1100         return uri;
1101     }
1102     int32_t id;
1103     if (!StrToInt(fileId, id)) {
1104         MEDIA_ERR_LOG("invalid fileuri %{private}s", uri.c_str());
1105         return uri;
1106     }
1107     int32_t realId = 0;
1108     MediaType type;
1109     if ((pureUri.find(MEDIALIBRARY_TYPE_IMAGE_URI) != string::npos)) {
1110         type = MediaType::MEDIA_TYPE_IMAGE;
1111         realId = static_cast<int32_t>(GetRealIdByTable(id, PhotoColumn::PHOTOS_TABLE));
1112     } else if (pureUri.find(MEDIALIBRARY_TYPE_VIDEO_URI) != string::npos) {
1113         type = MediaType::MEDIA_TYPE_VIDEO;
1114         realId = static_cast<int32_t>(GetRealIdByTable(id, PhotoColumn::PHOTOS_TABLE));
1115     } else if ((pureUri.find(MEDIALIBRARY_TYPE_AUDIO_URI) != string::npos)) {
1116         type = MediaType::MEDIA_TYPE_AUDIO;
1117         realId = static_cast<int32_t>(GetRealIdByTable(id, AudioColumn::AUDIOS_TABLE));
1118     } else {
1119         type = MediaType::MEDIA_TYPE_FILE;
1120         realId = static_cast<int32_t>(GetRealIdByTable(id, MEDIALIBRARY_TABLE));
1121     }
1122     string extrUri;
1123     if (fileUri.IsApi10()) {
1124         string displayName;
1125         GetExtrParamFromUri(pureUri, displayName);
1126         extrUri = GetExtraUri(displayName, fileUri.GetFilePath(), false);
1127     }
1128 
1129     MediaFileUri realUri(type, to_string(realId), fileUri.GetNetworkId(),
1130         (fileUri.IsApi10() ? MEDIA_API_VERSION_V10 : MEDIA_API_VERSION_V9), (fileUri.IsApi10() ? extrUri : ""));
1131 
1132     if (suffixUri.empty()) {
1133         return realUri.ToString();
1134     }
1135     return realUri.ToString() + suffixUri;
1136 }
1137 
1138 #ifdef MEDIALIBRARY_COMPATIBILITY
1139 string MediaFileUtils::GetTableFromVirtualUri(const std::string &virtualUri)
1140 {
1141     MediaFileUri uri(virtualUri);
1142     if (!uri.IsValid()) {
1143         MEDIA_ERR_LOG("virtual uri:%{private}s is invalid", virtualUri.c_str());
1144         return "";
1145     }
1146     string virtualId = uri.GetFileId();
1147     if (std::all_of(virtualId.begin(), virtualId.end(), ::isdigit)) {
1148         int64_t id = stol(virtualId);
1149         int64_t remainNumber = id % VIRTUAL_ID_DIVIDER;
1150         switch (remainNumber) {
1151             case VIRTUAL_ID_DIVIDER - PHOTO_VIRTUAL_IDENTIFIER:
1152                 return PhotoColumn::PHOTOS_TABLE;
1153             case VIRTUAL_ID_DIVIDER - AUDIO_VIRTUAL_IDENTIFIER:
1154                 return AudioColumn::AUDIOS_TABLE;
1155             case VIRTUAL_ID_DIVIDER - FILE_VIRTUAL_IDENTIFIER:
1156                 return MEDIALIBRARY_TABLE;
1157             default:
1158                 MEDIA_ERR_LOG("virtualId:%{public}ld is wrong", (long) id);
1159                 return "";
1160         }
1161     } else {
1162         MEDIA_ERR_LOG("virtual uri:%{private}s is invalid, can not get id", virtualUri.c_str());
1163         return "";
1164     }
1165 }
1166 #endif
1167 
1168 bool MediaFileUtils::IsUriV10(const string &mediaType)
1169 {
1170     return mediaType == URI_TYPE_PHOTO ||
1171         mediaType == URI_TYPE_PHOTO_ALBUM ||
1172         mediaType == URI_TYPE_AUDIO_V10;
1173 }
1174 
1175 bool MediaFileUtils::IsFileTablePath(const string &path)
1176 {
1177     if (path.empty() || path.size() <= ROOT_MEDIA_DIR.size()) {
1178         return false;
1179     }
1180 
1181     if (path.find(ROOT_MEDIA_DIR) == string::npos) {
1182         return false;
1183     }
1184 
1185     string relativePath = path.substr(ROOT_MEDIA_DIR.size());
1186     if ((relativePath.find(DOCS_PATH) == 0)) {
1187         return true;
1188     }
1189     return false;
1190 }
1191 
1192 bool MediaFileUtils::IsPhotoTablePath(const string &path)
1193 {
1194     if (path.empty() || path.size() <= ROOT_MEDIA_DIR.size()) {
1195         return false;
1196     }
1197 
1198     if (path.find(ROOT_MEDIA_DIR) == string::npos) {
1199         return false;
1200     }
1201 
1202     string relativePath = path.substr(ROOT_MEDIA_DIR.size());
1203 
1204     const vector<string> photoPathVector = {
1205         PHOTO_BUCKET, PIC_DIR_VALUES, VIDEO_DIR_VALUES, CAMERA_DIR_VALUES
1206     };
1207     for (auto &photoPath : photoPathVector) {
1208         if (relativePath.find(photoPath) == 0) {
1209             return true;
1210         }
1211     }
1212     return false;
1213 }
1214 
1215 bool MediaFileUtils::StartsWith(const std::string &str, const std::string &prefix)
1216 {
1217     return str.compare(0, prefix.size(), prefix) == 0;
1218 }
1219 
1220 void MediaFileUtils::UriAppendKeyValue(string &uri, const string &key, std::string value)
1221 {
1222     string uriKey = key + '=';
1223     if (uri.find(uriKey) != string::npos) {
1224         return;
1225     }
1226 
1227     char queryMark = (uri.find('?') == string::npos) ? '?' : '&';
1228     string append = queryMark + key + '=' + value;
1229 
1230     size_t pos = uri.find('#');
1231     if (pos == string::npos) {
1232         uri += append;
1233     } else {
1234         uri.insert(pos, append);
1235     }
1236 }
1237 
1238 string MediaFileUtils::GetExtraUri(const string &displayName, const string &path, const bool isNeedEncode)
1239 {
1240     string extraUri = "/" + GetTitleFromDisplayName(GetFileName(path)) + "/" + displayName;
1241     if (!isNeedEncode) {
1242         return extraUri;
1243     }
1244     return MediaFileUtils::Encode(extraUri);
1245 }
1246 
1247 string MediaFileUtils::GetUriByExtrConditions(const string &prefix, const string &fileId, const string &suffix)
1248 {
1249     return prefix + fileId + suffix;
1250 }
1251 
1252 string MediaFileUtils::Encode(const string &uri)
1253 {
1254     const unordered_set<char> uriCompentsSet = {
1255         ';', ',', '/', '?', ':', '@', '&',
1256         '=', '+', '$', '-', '_', '.', '!',
1257         '~', '*', '(', ')', '\''
1258     };
1259     const int32_t encodeLen = 2;
1260     ostringstream outPutStream;
1261     outPutStream.fill('0');
1262     outPutStream << std::hex;
1263 
1264     for (unsigned char tmpChar : uri) {
1265         if (std::isalnum(tmpChar) || uriCompentsSet.find(tmpChar) != uriCompentsSet.end()) {
1266             outPutStream << tmpChar;
1267         } else {
1268             outPutStream << std::uppercase;
1269             outPutStream << '%' << std::setw(encodeLen) << static_cast<unsigned int>(tmpChar);
1270             outPutStream << std::nouppercase;
1271         }
1272     }
1273 
1274     return outPutStream.str();
1275 }
1276 
AddDocsToRelativePath(const string & relativePath)1277 string MediaFileUtils::AddDocsToRelativePath(const string &relativePath)
1278 {
1279     if (MediaFileUtils::StartsWith(relativePath, DOC_DIR_VALUES) ||
1280         MediaFileUtils::StartsWith(relativePath, DOWNLOAD_DIR_VALUES)) {
1281         return DOCS_PATH + relativePath;
1282     }
1283     return relativePath;
1284 }
1285 
RemoveDocsFromRelativePath(const string & relativePath)1286 string MediaFileUtils::RemoveDocsFromRelativePath(const string &relativePath)
1287 {
1288     if (MediaFileUtils::StartsWith(relativePath, DOCS_PATH)) {
1289         return relativePath.substr(DOCS_PATH.size());
1290     }
1291     return relativePath;
1292 }
1293 
Timespec2Millisecond(const struct timespec & time)1294 int64_t MediaFileUtils::Timespec2Millisecond(const struct timespec &time)
1295 {
1296     return time.tv_sec * MSEC_TO_SEC + time.tv_nsec / MSEC_TO_NSEC;
1297 }
1298 } // namespace OHOS::Media
1299