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