• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 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 
16 #include "mimetype_utils.h"
17 
18 #include <algorithm>
19 #include <fstream>
20 #include <sys/stat.h>
21 #include <sstream>
22 #include <fcntl.h>
23 
24 #include "avmetadatahelper.h"
25 #include "directory_ex.h"
26 #include "image_source.h"
27 #include "media_log.h"
28 #include "medialibrary_errno.h"
29 #include "medialibrary_tracer.h"
30 #include "media_file_utils.h"
31 
32 #define O_RDONLY 00
33 
34 using std::string;
35 using std::vector;
36 using std::unordered_map;
37 using namespace nlohmann;
38 
39 namespace OHOS {
40 namespace Media {
41 using MimeTypeMap = unordered_map<string, vector<string>>;
42 
43 MimeTypeMap MimeTypeUtils::mediaJsonMap_;
44 const string MIMETYPE_JSON_PATH = "/system/etc/userfilemanager/userfilemanager_mimetypes.json";
45 const string DEFAULT_MIME_TYPE = "application/octet-stream";
46 
47 /**
48  * The format of the target json file:
49  * First floor: Media type string, such as image, video, audio, etc.
50  * Second floor: Mime type string
51  * Third floor: Extension array.
52 */
CreateMapFromJson()53 void MimeTypeUtils::CreateMapFromJson()
54 {
55     std::ifstream jFile(MIMETYPE_JSON_PATH);
56     if (!jFile.is_open()) {
57         MEDIA_ERR_LOG("Failed to open: %{private}s", MIMETYPE_JSON_PATH.c_str());
58         return;
59     }
60     json firstFloorObjs;
61     jFile >> firstFloorObjs;
62     jFile.close();
63     for (auto& firstFloorObj : firstFloorObjs.items()) {
64         json secondFloorJsons = json::parse(firstFloorObj.value().dump(), nullptr, false);
65         if (secondFloorJsons.is_discarded() || secondFloorJsons.empty()) {
66             MEDIA_ERR_LOG("parse secondFloorJsons failed");
67             return;
68         }
69         for (auto& secondFloorJson : secondFloorJsons.items()) {
70             json thirdFloorJsons = json::parse(secondFloorJson.value().dump(), nullptr, false);
71             if (thirdFloorJsons.is_discarded() || thirdFloorJsons.empty()) {
72                 MEDIA_ERR_LOG("parse thirdFloorJsons failed");
73                 return;
74             }
75             // Key: MimeType, Value: Extension array.
76             mediaJsonMap_.insert(std::pair<string, vector<string>>(secondFloorJson.key(), thirdFloorJsons));
77         }
78     }
79 }
80 
IsMimeTypeMapEmpty()81 bool MimeTypeUtils::IsMimeTypeMapEmpty()
82 {
83     return mediaJsonMap_.empty();
84 }
85 
InitMimeTypeMap()86 int32_t MimeTypeUtils::InitMimeTypeMap()
87 {
88     CreateMapFromJson();
89     if (mediaJsonMap_.empty()) {
90         return E_FAIL;
91     }
92     return E_OK;
93 }
94 
GetImageMimetype(const string & filePath,string & mimeType)95 int32_t MimeTypeUtils::GetImageMimetype(const string &filePath, string &mimeType)
96 {
97     SourceOptions opts;
98     uint32_t err = E_OK;
99     MediaLibraryTracer tracer;
100     tracer.Start("ImageSource::CreateImageSource");
101     std::unique_ptr<ImageSource> imageSource = ImageSource::CreateImageSource(filePath, opts, err);
102     tracer.Finish();
103     CHECK_AND_RETURN_RET_LOG(imageSource != nullptr, E_INVALID_VALUES,
104         "CreateImageSource failed, err: %{public}d", err);
105     tracer.Start("imageSource->GetImageInfo");
106     ImageInfo imageInfo;
107     err = imageSource->GetImageInfo(0, imageInfo);
108     tracer.Finish();
109     CHECK_AND_RETURN_RET_LOG(err == E_OK, E_INVALID_VALUES, "GetImageInfo failed, err: %{public}d", err);
110     mimeType = imageInfo.encodedFormat;
111     CHECK_AND_RETURN_RET_LOG(mimeType != "", E_INVALID_VALUES, "failed to get encodedFormat");
112     return E_OK;
113 }
114 
GetVideoMimetype(const string & filePath,string & mimeType)115 int32_t MimeTypeUtils::GetVideoMimetype(const string &filePath, string &mimeType)
116 {
117     MediaLibraryTracer tracer;
118     tracer.Start("avMetadataHelper->open");
119     std::shared_ptr<AVMetadataHelper> avMetadataHelper = AVMetadataHelperFactory::CreateAVMetadataHelper();
120     CHECK_AND_RETURN_RET_LOG(avMetadataHelper != nullptr, E_INVALID_VALUES,
121         "CreateAVMetadataHelper fail!");
122     int32_t fd = open(filePath.c_str(), O_RDONLY);
123     tracer.Finish();
124     CHECK_AND_RETURN_RET_LOG(fd > 0, E_SYSCALL, "Open file descriptor failed, errno = %{public}d", errno);
125 
126     struct stat64 st;
127     if (fstat64(fd, &st) != 0) {
128         MEDIA_ERR_LOG("Get file state failed for the given fd");
129         (void)close(fd);
130         return E_SYSCALL;
131     }
132 
133     tracer.Start("avMetadataHelper->SetSource");
134     int32_t err = avMetadataHelper->SetSource(fd, 0, static_cast<int64_t>(st.st_size), AV_META_USAGE_META_ONLY);
135     tracer.Finish();
136     if (err != E_OK) {
137         MEDIA_ERR_LOG("SetSource failed for file descriptor, err: %{public}d", err);
138         (void)close(fd);
139         return E_AVMETADATA;
140     }
141     tracer.Start("avMetadataHelper->ResolveMetadata");
142     std::unordered_map<int32_t, std::string> resultMap = avMetadataHelper->ResolveMetadata();
143     tracer.Finish();
144     (void)close(fd);
145     CHECK_AND_RETURN_RET_LOG(resultMap.find(AV_KEY_MIME_TYPE) != resultMap.end(), E_INVALID_VALUES,
146         "failed to get AV_KEY_MIME_TYPE");
147     mimeType = resultMap.at(AV_KEY_MIME_TYPE);
148     CHECK_AND_RETURN_RET_LOG(mimeType != "", E_INVALID_VALUES, "AV_KEY_MIME_TYPE empty");
149     return E_OK;
150 }
151 
GetMimeTypeFromContent(const string & filePath)152 string MimeTypeUtils::GetMimeTypeFromContent(const string &filePath)
153 {
154     CHECK_AND_RETURN_RET_LOG(filePath != "", "", "empty file path");
155     string extension = MediaFileUtils::GetExtensionFromPath(filePath);
156     string mimeType = GetMimeTypeFromExtension(extension);
157     string absFilePath;
158     CHECK_AND_RETURN_RET_LOG(PathToRealPath(filePath, absFilePath),
159         mimeType, "failed to transfer realpath: %{private}s", filePath.c_str());
160     int32_t mediaType = GetMediaTypeFromMimeType(mimeType);
161     int32_t err = -1;
162     if (mediaType == MEDIA_TYPE_IMAGE) {
163         err = GetImageMimetype(absFilePath, mimeType);
164     } else if (mediaType == MEDIA_TYPE_VIDEO) {
165         err = GetVideoMimetype(absFilePath, mimeType);
166     } else {
167         MEDIA_ERR_LOG("Invalid mediaType: %{public}d", mediaType);
168         return mimeType;
169     }
170     if (err != E_OK) {
171         mimeType = GetMimeTypeFromExtension(extension);
172     }
173     MEDIA_INFO_LOG("GetMimeTypeFromContent mimeType: %{public}s, err: %{public}d",
174         mimeType.c_str(), err);
175     return mimeType;
176 }
177 
GetMimeTypeFromExtension(const string & extension)178 string MimeTypeUtils::GetMimeTypeFromExtension(const string &extension)
179 {
180     return GetMimeTypeFromExtension(extension, mediaJsonMap_);
181 }
182 
GetMimeTypeFromExtension(const string & extension,const MimeTypeMap & mimeTypeMap)183 string MimeTypeUtils::GetMimeTypeFromExtension(const string &extension,
184     const MimeTypeMap &mimeTypeMap)
185 {
186     std::string tmp = std::move(extension);
187     std::transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower);
188     for (auto &item : mimeTypeMap) {
189         for (auto &ext : item.second) {
190             if (ext == tmp) {
191                 return item.first;
192             }
193         }
194     }
195     return DEFAULT_MIME_TYPE;
196 }
197 
GetMediaTypeFromMimeType(const string & mimeType)198 MediaType MimeTypeUtils::GetMediaTypeFromMimeType(const string &mimeType)
199 {
200     size_t pos = mimeType.find_first_of("/");
201     if (pos == string::npos) {
202         MEDIA_ERR_LOG("Invalid mime type: %{private}s", mimeType.c_str());
203         return MEDIA_TYPE_FILE;
204     }
205     string prefix = mimeType.substr(0, pos);
206     if (prefix == "audio") {
207         return MEDIA_TYPE_AUDIO;
208     } else if (prefix == "video") {
209         return MEDIA_TYPE_VIDEO;
210     } else if (prefix == "image") {
211         return MEDIA_TYPE_IMAGE;
212     } else {
213         return MEDIA_TYPE_FILE;
214     }
215 }
216 }
217 }
218