1 /*
2  * Copyright (C) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #define MLOG_TAG "Scanner"
16 
17 #include "ringtone_metadata_extractor.h"
18 
19 #include <fcntl.h>
20 #include <sys/stat.h>
21 
22 #include "directory_ex.h"
23 #include "ringtone_file_utils.h"
24 #include "ringtone_log.h"
25 #include "ringtone_errno.h"
26 
27 namespace OHOS {
28 namespace Media {
29 using namespace std;
30 
31 template <class Type>
stringToNum(const string & str)32 static Type stringToNum(const string &str)
33 {
34     std::istringstream iss(str);
35     Type num;
36     iss >> num;
37     return num;
38 }
39 
convertTimeStr2TimeStamp(string & timeStr)40 static time_t convertTimeStr2TimeStamp(string &timeStr)
41 {
42     struct tm timeinfo;
43     strptime(timeStr.c_str(), "%Y-%m-%d %H:%M:%S",  &timeinfo);
44     time_t timeStamp = mktime(&timeinfo);
45     return timeStamp;
46 }
47 
PopulateExtractedAVMetadataOne(const std::unordered_map<int32_t,std::string> & resultMap,std::unique_ptr<RingtoneMetadata> & data)48 void PopulateExtractedAVMetadataOne(const std::unordered_map<int32_t, std::string> &resultMap,
49     std::unique_ptr<RingtoneMetadata> &data)
50 {
51     int32_t intTempMeta;
52 
53     string strTemp = resultMap.at(Media::AV_KEY_DURATION);
54     if (strTemp != "") {
55         intTempMeta = stringToNum<int32_t>(strTemp);
56         data->SetDuration(intTempMeta);
57     }
58 
59     strTemp = resultMap.at(Media::AV_KEY_MIME_TYPE);
60     if (strTemp != "") {
61         data->SetMimeType(strTemp);
62     }
63 }
64 
PopulateExtractedAVMetadataTwo(const std::unordered_map<int32_t,std::string> & resultMap,std::unique_ptr<RingtoneMetadata> & data)65 void PopulateExtractedAVMetadataTwo(const std::unordered_map<int32_t, std::string> &resultMap,
66     std::unique_ptr<RingtoneMetadata> &data)
67 {
68     string strTemp = resultMap.at(Media::AV_KEY_DATE_TIME_FORMAT);
69     if (strTemp != "") {
70         int64_t int64TempMeta = convertTimeStr2TimeStamp(strTemp);
71         if (int64TempMeta < 0) {
72             data->SetDateTaken(data->GetDateModified() / MSEC_TO_SEC);
73         } else {
74             data->SetDateTaken(int64TempMeta);
75         }
76     } else {
77         // use modified time as date taken time when date taken not set
78         data->SetDateTaken(data->GetDateModified() / MSEC_TO_SEC);
79     }
80 
81     strTemp = resultMap.at(Media::AV_KEY_TITLE);
82     if (!strTemp.empty()) {
83         data->SetTitle(strTemp);
84     }
85 }
86 
FillExtractedMetadata(const std::unordered_map<int32_t,std::string> & resultMap,std::unique_ptr<RingtoneMetadata> & data)87 void RingtoneMetadataExtractor::FillExtractedMetadata(const std::unordered_map<int32_t, std::string> &resultMap,
88     std::unique_ptr<RingtoneMetadata> &data)
89 {
90     PopulateExtractedAVMetadataOne(resultMap, data);
91     PopulateExtractedAVMetadataTwo(resultMap, data);
92 }
93 
ExtractAudioMetadata(std::unique_ptr<RingtoneMetadata> & data)94 int32_t RingtoneMetadataExtractor::ExtractAudioMetadata(std::unique_ptr<RingtoneMetadata> &data)
95 {
96     std::shared_ptr<Media::AVMetadataHelper> avMetadataHelper =
97         Media::AVMetadataHelperFactory::CreateAVMetadataHelper();
98     if (avMetadataHelper == nullptr) {
99         RINGTONE_ERR_LOG("AV RingtoneMetadata helper is null");
100         return E_AVMETADATA;
101     }
102 
103     string absFilePath;
104     if (!PathToRealPath(data->GetData(), absFilePath)) {
105         RINGTONE_ERR_LOG("AV RingtoneMetadata is not real path, file path: %{public}s", data->GetData().c_str());
106         return E_AVMETADATA;
107     }
108     if (absFilePath.empty()) {
109         RINGTONE_ERR_LOG("Failed to obtain the canonical path for source path: %{public}s %{public}d",
110             absFilePath.c_str(), errno);
111         return E_AVMETADATA;
112     }
113 
114     int32_t fd = open(absFilePath.c_str(), O_RDONLY);
115     if (fd <= 0) {
116         RINGTONE_ERR_LOG("Open file descriptor failed, errno = %{public}d", errno);
117         return E_SYSCALL;
118     }
119     struct stat64 st;
120     if (fstat64(fd, &st) != 0) {
121         RINGTONE_ERR_LOG("Get file state failed for the given fd");
122         (void)close(fd);
123         return E_SYSCALL;
124     }
125 
126     int32_t err = avMetadataHelper->SetSource(fd, 0, static_cast<int64_t>(st.st_size), Media::AV_META_USAGE_META_ONLY);
127     if (err != 0) {
128         RINGTONE_ERR_LOG("SetSource failed for the given file descriptor, err = %{public}d", err);
129         (void)close(fd);
130         return E_AVMETADATA;
131     } else {
132         std::unordered_map<int32_t, std::string> resultMap = avMetadataHelper->ResolveMetadata();
133         if (!resultMap.empty()) {
134             FillExtractedMetadata(resultMap, data);
135         }
136     }
137 
138     (void)close(fd);
139 
140     return E_OK;
141 }
142 
Extract(std::unique_ptr<RingtoneMetadata> & data)143 int32_t RingtoneMetadataExtractor::Extract(std::unique_ptr<RingtoneMetadata> &data)
144 {
145     return ExtractAudioMetadata(data);
146 }
147 } // namespace Media
148 } // namespace OHOS
149