improved parsing ID3 genres
This commit is contained in:
parent
19593d4c24
commit
617679e001
|
@ -16,8 +16,9 @@ using namespace std;
|
|||
using namespace IoUtilities;
|
||||
|
||||
/*!
|
||||
* \remarks Nothing of this code has been tested yet. These classes are
|
||||
* not used by the rest of the library (currently).
|
||||
* \file aacframe.cpp
|
||||
* \remarks Nothing of this code has been tested yet. It is currently not used
|
||||
* in the rest of the library.
|
||||
*/
|
||||
|
||||
namespace Media {
|
||||
|
|
|
@ -32,7 +32,16 @@ const char **Id3Genres::genreNames()
|
|||
"Easy Listening", "Acoustic", "Humour", "Speech", "Chanson", "Opera", "Chamber Music",
|
||||
"Sonata", "Symphony", "Booty Bass", "Primus", "Porn Groove", "Satire", "Slow Jam",
|
||||
"Club", "Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul",
|
||||
"Freestyle", "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall"
|
||||
"Freestyle", "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall",
|
||||
"Goa", "Drum & Bass", "Club-House", "Hardcore Techno", "Terror", "Indie", "BritPop",
|
||||
"Negerpunk", "Polsk Punk", "Beat", "Christian Gangsta Rap", "Heavy Metal", "Black Metal",
|
||||
"Crossover", "Contemporary Christian", "Christian Rock", "Merengue", "Salsa", "Thrash Metal",
|
||||
"Anime", "Jpop", "Synthpop", "Abstract", "Art Rock", "Baroque", "Bhangra", "Big Beat", "Breakbeat",
|
||||
"Chillout", "Downtempo", "Dub", "EBM", "Eclectic", "Electro", "Electroclash", "Emo", "Experimental",
|
||||
"Garage", "Global", "IDM", "Illbient", "Industro-Goth", "Jam Band", "Krautrock", "Leftfield", "Lounge",
|
||||
"Math Rock", "New Romantic", "Nu-Breakz", "Post-Punk", "Post-Rock", "Psytrance", "Shoegaze", "Space Rock",
|
||||
"Trop Rock", "World Music", "Neoclassical", "Audiobook", "Audio Theatre", "Neue Deutsche Welle", "Podcast",
|
||||
"Indie Rock", "G-Funk", "Dubstep", "Garage Rock", "Psybient"
|
||||
};
|
||||
return names;
|
||||
}
|
||||
|
@ -43,13 +52,9 @@ const char **Id3Genres::genreNames()
|
|||
int Id3Genres::indexFromString(const string &genre)
|
||||
{
|
||||
const char **ptr = genreNames();
|
||||
int index = 0;
|
||||
while(index < genreCount()) {
|
||||
for(int index = 0; index < genreCount(); ++ptr, ++index) {
|
||||
if(genre == *ptr) {
|
||||
return index;
|
||||
} else {
|
||||
++ptr;
|
||||
++index;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -14,8 +14,8 @@ class LIB_EXPORT Id3Genres
|
|||
public:
|
||||
static const char *stringFromIndex(int index);
|
||||
static int indexFromString(const std::string &genre);
|
||||
static bool isIndexSupported(int index);
|
||||
static int genreCount();
|
||||
static constexpr int genreCount();
|
||||
static constexpr bool isIndexSupported(int index);
|
||||
|
||||
private:
|
||||
static const char **genreNames();
|
||||
|
@ -30,20 +30,20 @@ inline const char *Id3Genres::stringFromIndex(int index)
|
|||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns an indication whether the specified numerical denotation is
|
||||
* supported by this class.
|
||||
* \brief Returns the number of supported genres.
|
||||
*/
|
||||
inline bool Id3Genres::isIndexSupported(int index)
|
||||
constexpr int Id3Genres::genreCount()
|
||||
{
|
||||
return index >= 0 && index < genreCount();
|
||||
return 192;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the number of supported genres.
|
||||
* \brief Returns an indication whether the specified numerical denotation is
|
||||
* supported by this class.
|
||||
*/
|
||||
inline int Id3Genres::genreCount()
|
||||
constexpr bool Id3Genres::isIndexSupported(int index)
|
||||
{
|
||||
return 126;
|
||||
return index >= 0 && index < genreCount();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -49,6 +49,52 @@ Id3v2Frame::Id3v2Frame(const identifierType &id, const TagValue &value, const by
|
|||
m_padding(false)
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Helper function to parse the genre index.
|
||||
* \returns Returns the genre index or -1 if the specified string does not denote a genre index.
|
||||
*/
|
||||
template<class stringtype>
|
||||
int parseGenreIndex(const stringtype &denotation, bool isBigEndian = false)
|
||||
{
|
||||
int index = -1;
|
||||
for(auto c : denotation) {
|
||||
if(sizeof(typename stringtype::value_type) == 2 && isBigEndian != CONVERSION_UTILITIES_IS_BYTE_ORDER_BIG_ENDIAN) {
|
||||
c = swapOrder(static_cast<uint16>(c));
|
||||
}
|
||||
if(index == -1) {
|
||||
switch(c) {
|
||||
case ' ':
|
||||
break;
|
||||
case '(':
|
||||
index = 0;
|
||||
break;
|
||||
case '\0':
|
||||
return -1;
|
||||
default:
|
||||
if(c >= '0' && c <= '9') {
|
||||
index = c - '0';
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch(c) {
|
||||
case ')':
|
||||
return index;
|
||||
case '\0':
|
||||
return index;
|
||||
default:
|
||||
if(c >= '0' && c <= '9') {
|
||||
index = index * 10 + c - '0';
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Parses a frame from the stream read using the specified \a reader.
|
||||
*
|
||||
|
@ -195,8 +241,7 @@ void Id3v2Frame::parse(BinaryReader &reader, const uint32 version, const uint32
|
|||
double milliseconds;
|
||||
try {
|
||||
if(characterSize(dataEncoding) > 1) {
|
||||
wstring millisecondsStr = parseWideString(buffer.get() + 1, m_dataSize - 1, dataEncoding);
|
||||
milliseconds = ConversionUtilities::stringToNumber<double, wstring>(millisecondsStr, 10);
|
||||
milliseconds = ConversionUtilities::stringToNumber<double>(parseWideString(buffer.get() + 1, m_dataSize - 1, dataEncoding), 10);
|
||||
} else {
|
||||
milliseconds = ConversionUtilities::stringToNumber<double>(parseString(buffer.get() + 1, m_dataSize - 1, dataEncoding), 10);
|
||||
}
|
||||
|
@ -208,22 +253,17 @@ void Id3v2Frame::parse(BinaryReader &reader, const uint32 version, const uint32
|
|||
} else if((version >= 3 && id() == Id3v2FrameIds::lGenre) || (version < 3 && id() == Id3v2FrameIds::sGenre)) {
|
||||
// genre/content type
|
||||
int genreIndex;
|
||||
try {
|
||||
if(characterSize(dataEncoding) > 1) {
|
||||
wstring indexStr = parseWideString(buffer.get() + 1, m_dataSize - 1, dataEncoding);
|
||||
if(indexStr.front() == L'(' && indexStr.back() == L')') {
|
||||
indexStr = indexStr.substr(1, indexStr.length() - 2);
|
||||
}
|
||||
genreIndex = ConversionUtilities::stringToNumber<int, wstring>(indexStr, 10);
|
||||
} else {
|
||||
string indexStr = parseString(buffer.get() + 1, m_dataSize - 1, dataEncoding);
|
||||
if(indexStr.front() == '(' && indexStr.back() == ')') {
|
||||
indexStr = indexStr.substr(1, indexStr.length() - 2);
|
||||
}
|
||||
genreIndex = ConversionUtilities::stringToNumber<int>(indexStr, 10);
|
||||
}
|
||||
value().assignStandardGenreIndex(genreIndex); // genre is specified as ID3 genre number
|
||||
} catch(ConversionException &) {
|
||||
if(characterSize(dataEncoding) > 1) {
|
||||
auto genreDenotation = parseWideString(buffer.get() + 1, m_dataSize - 1, dataEncoding);
|
||||
genreIndex = parseGenreIndex(genreDenotation, dataEncoding == TagTextEncoding::Utf16BigEndian);
|
||||
} else {
|
||||
auto genreDenotation = parseString(buffer.get() + 1, m_dataSize - 1, dataEncoding);
|
||||
genreIndex = parseGenreIndex(genreDenotation);
|
||||
}
|
||||
if(genreIndex != -1) {
|
||||
// genre is specified as ID3 genre number
|
||||
value().assignStandardGenreIndex(genreIndex);
|
||||
} else {
|
||||
// genre is specified as string
|
||||
// string might be null terminated
|
||||
auto substr = parseSubstring(buffer.get() + 1, m_dataSize - 1, dataEncoding);
|
||||
|
@ -600,12 +640,12 @@ string Id3v2Frame::parseString(const char *buffer, size_t dataSize, TagTextEncod
|
|||
/*!
|
||||
* \brief Parses a substring in the specified \a buffer.
|
||||
*
|
||||
* Same as Id3v2Frame::parseSubstring() but returns the substring as wstring object.
|
||||
* Same as Id3v2Frame::parseSubstring() but returns the substring as u16string object.
|
||||
*/
|
||||
wstring Id3v2Frame::parseWideString(const char *buffer, size_t dataSize, TagTextEncoding &encoding, bool addWarnings)
|
||||
u16string Id3v2Frame::parseWideString(const char *buffer, size_t dataSize, TagTextEncoding &encoding, bool addWarnings)
|
||||
{
|
||||
auto substr = parseSubstring(buffer, dataSize, encoding, addWarnings);
|
||||
return wstring(reinterpret_cast<wstring::const_pointer>(get<0>(substr)), get<1>(substr) / 2);
|
||||
return u16string(reinterpret_cast<u16string::const_pointer>(get<0>(substr)), get<1>(substr) / 2);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
@ -137,7 +137,7 @@ public:
|
|||
TagTextEncoding parseTextEncodingByte(byte textEncodingByte);
|
||||
std::tuple<const char *, size_t, const char *> parseSubstring(const char *buffer, std::size_t maxSize, TagTextEncoding &encoding, bool addWarnings = false);
|
||||
std::string parseString(const char *buffer, std::size_t maxSize, TagTextEncoding &encoding, bool addWarnings = false);
|
||||
std::wstring parseWideString(const char *buffer, std::size_t dataSize, TagTextEncoding &encoding, bool addWarnings = false);
|
||||
std::u16string parseWideString(const char *buffer, std::size_t dataSize, TagTextEncoding &encoding, bool addWarnings = false);
|
||||
void parseLegacyPicture(const char *buffer, size_t maxSize, TagValue &tagValue, byte &typeInfo);
|
||||
void parsePicture(const char *buffer, size_t maxSize, TagValue &tagValue, byte &typeInfo);
|
||||
void parseComment(const char *buffer, size_t maxSize, TagValue &tagValue);
|
||||
|
|
Loading…
Reference in New Issue