improved parsing ID3 genres

This commit is contained in:
Martchus 2016-02-23 20:33:00 +01:00
parent 19593d4c24
commit 617679e001
5 changed files with 85 additions and 39 deletions

View File

@ -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 {

View File

@ -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;

View File

@ -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();
}
}

View File

@ -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);
}
/*!

View File

@ -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);