mirror of
https://github.com/taglib/taglib.git
synced 2025-06-03 09:08:09 -04:00
Update the TCON (genre) frame as we create it so that we don't keep ID3v2.3
formatted data sitting around waiting to be written to 2.4 tags. BUG:132018 git-svn-id: svn://anonsvn.kde.org/home/kde/trunk/kdesupport/taglib@578687 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
This commit is contained in:
parent
784f71409b
commit
f8d1b7bb4f
@ -215,7 +215,8 @@ void UserTextIdentificationFrame::setDescription(const String &s)
|
||||
TextIdentificationFrame::setText(l);
|
||||
}
|
||||
|
||||
UserTextIdentificationFrame *UserTextIdentificationFrame::find(ID3v2::Tag *tag, const String &description) // static
|
||||
UserTextIdentificationFrame *UserTextIdentificationFrame::find(
|
||||
ID3v2::Tag *tag, const String &description) // static
|
||||
{
|
||||
FrameList l = tag->frameList("TXXX");
|
||||
for(FrameList::Iterator it = l.begin(); it != l.end(); ++it) {
|
||||
@ -239,7 +240,7 @@ UserTextIdentificationFrame::UserTextIdentificationFrame(const ByteVector &data,
|
||||
void UserTextIdentificationFrame::checkFields()
|
||||
{
|
||||
int fields = fieldList().size();
|
||||
|
||||
|
||||
if(fields == 0)
|
||||
setDescription(String::null);
|
||||
if(fields <= 1)
|
||||
|
@ -121,6 +121,10 @@ Frame *FrameFactory::createFrame(const ByteVector &data, uint version) const
|
||||
|
||||
if(d->useDefaultEncoding)
|
||||
f->setTextEncoding(d->defaultEncoding);
|
||||
|
||||
if(frameID == "TCON")
|
||||
updateGenre(f);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
@ -311,3 +315,29 @@ void FrameFactory::convertFrame(const char *from, const char *to,
|
||||
|
||||
header->setFrameID(to);
|
||||
}
|
||||
|
||||
void FrameFactory::updateGenre(TextIdentificationFrame *frame) const
|
||||
{
|
||||
StringList fields;
|
||||
String s = frame->toString();
|
||||
|
||||
while(s.startsWith("(")) {
|
||||
|
||||
int closing = s.find(")");
|
||||
|
||||
if(closing < 0)
|
||||
break;
|
||||
|
||||
fields.append(s.substr(1, closing - 1));
|
||||
|
||||
s = s.substr(closing + 1);
|
||||
}
|
||||
|
||||
if(!s.isEmpty())
|
||||
fields.append(s);
|
||||
|
||||
if(fields.isEmpty())
|
||||
fields.append(String::null);
|
||||
|
||||
frame->setText(fields);
|
||||
}
|
||||
|
@ -29,6 +29,8 @@ namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
class TextIdentificationFrame;
|
||||
|
||||
//! A factory for creating ID3v2 frames
|
||||
|
||||
/*!
|
||||
@ -128,6 +130,8 @@ namespace TagLib {
|
||||
void convertFrame(const char *from, const char *to,
|
||||
Frame::Header *header) const;
|
||||
|
||||
void updateGenre(TextIdentificationFrame *frame) const;
|
||||
|
||||
static FrameFactory *factory;
|
||||
|
||||
class FrameFactoryPrivate;
|
||||
|
@ -124,69 +124,53 @@ String ID3v2::Tag::genre() const
|
||||
// should be separated by " / " instead of " ". For the moment to keep
|
||||
// the behavior the same as released versions it is being left with " ".
|
||||
|
||||
if(!d->frameListMap["TCON"].isEmpty() &&
|
||||
dynamic_cast<TextIdentificationFrame *>(d->frameListMap["TCON"].front()))
|
||||
if(d->frameListMap["TCON"].isEmpty() ||
|
||||
!dynamic_cast<TextIdentificationFrame *>(d->frameListMap["TCON"].front()))
|
||||
{
|
||||
Frame *frame = d->frameListMap["TCON"].front();
|
||||
|
||||
// ID3v2.4 lists genres as the fields in its frames field list. If the field
|
||||
// is simply a number it can be assumed that it is an ID3v1 genre number.
|
||||
// Here was assume that if an ID3v1 string is present that it should be
|
||||
// appended to the genre string. Multiple fields will be appended as the
|
||||
// string is built.
|
||||
|
||||
if(d->header.majorVersion() == 4) {
|
||||
TextIdentificationFrame *f = static_cast<TextIdentificationFrame *>(frame);
|
||||
StringList fields = f->fieldList();
|
||||
|
||||
String genreString;
|
||||
bool hasNumber = false;
|
||||
|
||||
for(StringList::ConstIterator it = fields.begin(); it != fields.end(); ++it) {
|
||||
bool isNumber = true;
|
||||
for(String::ConstIterator charIt = (*it).begin();
|
||||
isNumber && charIt != (*it).end();
|
||||
++charIt)
|
||||
{
|
||||
isNumber = *charIt >= '0' && *charIt <= '9';
|
||||
}
|
||||
|
||||
if(!genreString.isEmpty())
|
||||
genreString.append(' ');
|
||||
|
||||
if(isNumber) {
|
||||
int number = (*it).toInt();
|
||||
if(number >= 0 && number <= 255) {
|
||||
hasNumber = true;
|
||||
genreString.append(ID3v1::genre(number));
|
||||
}
|
||||
}
|
||||
else
|
||||
genreString.append(*it);
|
||||
}
|
||||
if(hasNumber)
|
||||
return genreString;
|
||||
}
|
||||
|
||||
String s = frame->toString();
|
||||
|
||||
// ID3v2.3 "content type" can contain a ID3v1 genre number in parenthesis at
|
||||
// the beginning of the field. If this is all that the field contains, do a
|
||||
// translation from that number to the name and return that. If there is a
|
||||
// string folloing the ID3v1 genre number, that is considered to be
|
||||
// authoritative and we return that instead. Or finally, the field may
|
||||
// simply be free text, in which case we just return the value.
|
||||
|
||||
int closing = s.find(")");
|
||||
if(s.substr(0, 1) == "(" && closing > 0) {
|
||||
if(closing == int(s.size() - 1))
|
||||
return ID3v1::genre(s.substr(1, s.size() - 2).toInt());
|
||||
else
|
||||
return s.substr(closing + 1);
|
||||
}
|
||||
return s;
|
||||
return String::null;
|
||||
}
|
||||
return String::null;
|
||||
|
||||
// ID3v2.4 lists genres as the fields in its frames field list. If the field
|
||||
// is simply a number it can be assumed that it is an ID3v1 genre number.
|
||||
// Here was assume that if an ID3v1 string is present that it should be
|
||||
// appended to the genre string. Multiple fields will be appended as the
|
||||
// string is built.
|
||||
|
||||
TextIdentificationFrame *f = static_cast<TextIdentificationFrame *>(
|
||||
d->frameListMap["TCON"].front());
|
||||
|
||||
StringList fields = f->fieldList();
|
||||
|
||||
String genreString;
|
||||
bool hasNumber = false;
|
||||
|
||||
for(StringList::ConstIterator it = fields.begin(); it != fields.end(); ++it) {
|
||||
|
||||
bool isNumber = true;
|
||||
|
||||
for(String::ConstIterator charIt = (*it).begin();
|
||||
isNumber && charIt != (*it).end();
|
||||
++charIt)
|
||||
{
|
||||
isNumber = *charIt >= '0' && *charIt <= '9';
|
||||
}
|
||||
|
||||
if(!genreString.isEmpty())
|
||||
genreString.append(' ');
|
||||
|
||||
if(isNumber) {
|
||||
int number = (*it).toInt();
|
||||
if(number >= 0 && number <= 255) {
|
||||
hasNumber = true;
|
||||
genreString.append(ID3v1::genre(number));
|
||||
}
|
||||
}
|
||||
else {
|
||||
genreString.append(*it);
|
||||
}
|
||||
}
|
||||
|
||||
return genreString;
|
||||
}
|
||||
|
||||
TagLib::uint ID3v2::Tag::year() const
|
||||
|
@ -287,6 +287,14 @@ int String::find(const String &s, int offset) const
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool String::startsWith(const String &s) const
|
||||
{
|
||||
if(s.length() > length())
|
||||
return false;
|
||||
|
||||
return substr(0, s.length()) == s;
|
||||
}
|
||||
|
||||
String String::substr(uint position, uint n) const
|
||||
{
|
||||
if(n > position + d->data.size())
|
||||
@ -325,6 +333,11 @@ TagLib::uint String::size() const
|
||||
return d->data.size();
|
||||
}
|
||||
|
||||
TagLib::uint String::length() const
|
||||
{
|
||||
return size();
|
||||
}
|
||||
|
||||
bool String::isEmpty() const
|
||||
{
|
||||
return d->data.size() == 0;
|
||||
|
@ -219,6 +219,11 @@ namespace TagLib {
|
||||
*/
|
||||
int find(const String &s, int offset = 0) const;
|
||||
|
||||
/*!
|
||||
* Returns true if the strings starts with the substring \a s.
|
||||
*/
|
||||
bool startsWith(const String &s) const;
|
||||
|
||||
/*!
|
||||
* Extract a substring from this string starting at \a position and
|
||||
* continuing for \a n characters.
|
||||
@ -243,6 +248,11 @@ namespace TagLib {
|
||||
*/
|
||||
uint size() const;
|
||||
|
||||
/*!
|
||||
* Returns the length of the string. Equivalent to size().
|
||||
*/
|
||||
uint length() const;
|
||||
|
||||
/*!
|
||||
* Returns true if the string is empty.
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user