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 ®exStr)
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(×);
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