1 #include "TagLibParser.h"
2 #include <stdlib.h>
3 #include <string.h>
4 #include <limits.h>
5 
6 #include <vector>
7 
8 #include <scx/Conv.h>
9 #include <scx/FileHelper.h>
10 #include <scx/IconvHelper.h>
11 using namespace scx;
12 
13 #include "CoverArt.h"
14 
15 #include <taglib/mpegfile.h>
16 
StringToStdString(const String & str)17 static string StringToStdString(const String& str)
18 {
19     if (str.isLatin1()) {
20         return str.to8Bit();
21     } else {
22         string stdStr;
23         const ByteVector& v = str.data(String::UTF16BE);
24         if (IconvHelper::ConvFromTo("UTF-16BE", "UTF-8", v.data(), v.size(), stdStr))
25             return stdStr;
26         else
27             return str.to8Bit();
28     }
29 }
30 
TagLibParser()31 TagLibParser::TagLibParser()
32 {
33     m_DumpHandlers["mp3"] = &DumpMp3Cover;
34     m_DumpHandlers["m4a"] = &DumpMp4Cover;
35 
36     m_StoreHandlers["mp3"] = &StoreMp3Cover;
37     m_StoreHandlers["m4a"] = &StoreMp4Cover;
38 }
39 
~TagLibParser()40 TagLibParser::~TagLibParser()
41 {
42     m_DumpHandlers.clear();
43     Close();
44 }
45 
FileSuffix() const46 vector<string> TagLibParser::FileSuffix() const
47 {
48     return { "*" };
49 }
50 
Open(const string & path)51 ErrorCode TagLibParser::Open(const string& path)
52 {
53     m_FileName = path;
54 
55     m_pFileRef = new FileRef(path.c_str(), true);//AudioProperties::);
56     if (!m_pFileRef->isNull() && m_pFileRef->tag() != nullptr) {
57         m_pTag = m_pFileRef->tag();
58         m_pProp = m_pFileRef->audioProperties();
59     }
60     return ErrorCode::Ok;
61 }
62 
Close()63 void TagLibParser::Close()
64 {
65     if (m_pFileRef != nullptr) {
66         delete m_pFileRef;
67         m_pFileRef = nullptr;
68         m_pTag = nullptr;
69         m_pProp = nullptr;
70     }
71 
72     m_FileName.clear();
73 }
74 
HasTag() const75 bool TagLibParser::HasTag() const
76 {
77     return (m_pTag != nullptr) ? !m_pTag->isEmpty() : false;
78 }
79 
Title() const80 string TagLibParser::Title() const
81 {
82     if (m_pTag != nullptr) {
83         return StringToStdString(m_pTag->title());
84     } else {
85         return "";
86     }
87 }
88 
Artist() const89 string TagLibParser::Artist() const
90 {
91     if (m_pTag != nullptr) {
92         return StringToStdString(m_pTag->artist());
93     } else {
94         return "";
95     }
96 }
97 
Album() const98 string TagLibParser::Album() const
99 {
100     if (m_pTag != nullptr) {
101         return StringToStdString(m_pTag->album());
102     } else {
103         return "";
104     }
105 }
106 
Comment() const107 string TagLibParser::Comment() const
108 {
109     if (m_pTag != nullptr) {
110         return StringToStdString(m_pTag->comment());
111     } else {
112         return "";
113     }
114 }
115 
Genre() const116 string TagLibParser::Genre() const
117 {
118     if (m_pTag != nullptr) {
119         return StringToStdString(m_pTag->genre());
120     } else {
121         return "";
122     }
123 }
124 
Year() const125 int32_t TagLibParser::Year() const
126 {
127     if (m_pTag != nullptr) {
128         return m_pTag->year();
129     } else {
130         return -1;
131     }
132 }
133 
Track() const134 int32_t TagLibParser::Track() const
135 {
136     if (m_pTag != nullptr) {
137         return m_pTag->track();
138     } else {
139         return -1;
140     }
141 }
142 
HasAudioProperty() const143 bool TagLibParser::HasAudioProperty() const
144 {
145     return (m_pProp != nullptr) ? true : false;
146 }
147 
Duration() const148 int32_t TagLibParser::Duration() const
149 {
150     if (m_pProp != nullptr) {
151         return m_pProp->length()*1000;
152     } else {
153         return 0;
154     }
155 }
156 
BitRate() const157 int32_t TagLibParser::BitRate() const
158 {
159     if (m_pProp != nullptr) {
160         return m_pProp->bitrate();
161     } else {
162         return 0;
163     }
164 }
165 
CanEdit() const166 bool TagLibParser::CanEdit() const
167 {
168     return true;
169 }
170 
Save()171 bool TagLibParser::Save()
172 {
173     const string& ext = ToLower(FileHelper::FileSuffix(m_FileName));
174     if (ext == "mp3") {
175         auto ref = dynamic_cast<TagLib::MPEG::File*>(m_pFileRef->file());
176         if (ref == nullptr) {
177             cout << "bad type" << endl;
178             return false;
179         }
180         return ref->save(TagLib::MPEG::File::TagTypes::ID3v2, true, 3, true);
181     } else {
182         return m_pFileRef != nullptr ? m_pFileRef->save() : false;
183     }
184 }
185 
SetTitle(const string & title)186 void TagLibParser::SetTitle(const string& title)
187 {
188     if (m_pTag != nullptr)
189         m_pTag->setTitle(title.c_str());
190 }
191 
SetArtist(const string & artist)192 void TagLibParser::SetArtist(const string& artist)
193 {
194     if (m_pTag != nullptr)
195         m_pTag->setArtist(artist.c_str());
196 }
197 
SetAlbum(const string & album)198 void TagLibParser::SetAlbum(const string& album)
199 {
200     if (m_pTag != nullptr)
201         m_pTag->setAlbum(album.c_str());
202 }
203 
SetComment(const string & comment)204 void TagLibParser::SetComment(const string& comment)
205 {
206     if (m_pTag != nullptr)
207         m_pTag->setComment(comment.c_str());
208 }
209 
SetGenre(const string & genre)210 void TagLibParser::SetGenre(const string& genre)
211 {
212     if (m_pTag != nullptr)
213         m_pTag->setGenre(genre.c_str());
214 }
215 
SetYear(int32_t year)216 void TagLibParser::SetYear(int32_t year)
217 {
218     if (m_pTag != nullptr)
219         m_pTag->setYear(year);
220 }
221 
SetTrack(int32_t track)222 void TagLibParser::SetTrack(int32_t track)
223 {
224     if (m_pTag != nullptr)
225         m_pTag->setTrack(track);
226 }
227 
DumpCoverArt(vector<char> & buf)228 CoverFormat TagLibParser::DumpCoverArt(vector<char>& buf)
229 {
230     if (m_FileName.empty())
231         return CoverFormat::None;
232 
233     const string& ext = ToLower(FileHelper::FileSuffix(m_FileName));
234 
235     if (m_DumpHandlers.find(ext) != m_DumpHandlers.end())
236         return m_DumpHandlers[ext](m_FileName, buf);
237     else
238         return CoverFormat::None;
239 }
240 
StoreCoverArt(CoverFormat fmt,const char * buf,size_t len)241 bool TagLibParser::StoreCoverArt(CoverFormat fmt, const char* buf, size_t len)
242 {
243     if (m_FileName.empty())
244         return false;
245 
246     const string& ext = ToLower(FileHelper::FileSuffix(m_FileName));
247 
248     if (m_StoreHandlers.find(ext) != m_StoreHandlers.end())
249         return m_StoreHandlers[ext](m_FileName, fmt, buf, len);
250     else
251         return false;
252 }
253