QString extractMBIDFromFile(TagLib::MPEG::File *file)
{
	TagLib::ID3v2::Tag *tag = file->ID3v2Tag();
	TagLib::ID3v2::FrameList ufid = tag->frameListMap()["UFID"];
	if (!ufid.isEmpty()) {
		for (TagLib::ID3v2::FrameList::Iterator i = ufid.begin(); i != ufid.end(); i++) {
			TagLib::ID3v2::UniqueFileIdentifierFrame *frame = dynamic_cast<TagLib::ID3v2::UniqueFileIdentifierFrame *>(*i);
			if (frame && frame->owner() == "http://musicbrainz.org") {
				TagLib::ByteVector id = frame->identifier();
				return QString::fromAscii(id.data(), id.size());
			}
		}
	}
	return QString();
}
Meta::FieldHash
ID3v2TagHelper::tags() const
{
    Meta::FieldHash data = TagHelper::tags();

    TagLib::ID3v2::FrameList list = m_tag->frameList();
    for( TagLib::ID3v2::FrameList::ConstIterator it = list.begin(); it != list.end(); ++it )
    {
        qint64 field;
        TagLib::String frameName  = TagLib::String( ( *it )->frameID() );
        if( ( field = fieldName( frameName ) ) )
        {
            if( field == Meta::valUniqueId )
            {
                TagLib::ID3v2::UniqueFileIdentifierFrame *frame =
                        dynamic_cast< TagLib::ID3v2::UniqueFileIdentifierFrame * >( *it );

                if( !frame )
                    continue;

                QString identifier = TStringToQString( TagLib::String( frame->identifier() ) );

                if( identifier.isEmpty() )
                    continue;

                if( frame->owner() == uidFieldName( UIDAFT ) && isValidUID( identifier, UIDAFT ) )
                    data.insert( Meta::valUniqueId, identifier );
                continue;
            }
            else if( field == Meta::valHasCover )
            {
                TagLib::ID3v2::AttachedPictureFrame *frame =
                        dynamic_cast< TagLib::ID3v2::AttachedPictureFrame * >( *it );

                if( !frame )
                    continue;

                if( ( frame->type() == TagLib::ID3v2::AttachedPictureFrame::FrontCover ||
                      frame->type() == TagLib::ID3v2::AttachedPictureFrame::Other ) &&
                    frame->picture().size() > MIN_COVER_SIZE ) // must be at least 1kb
                {
                    data.insert( Meta::valHasCover, true );
                }
                continue;
            }

            TagLib::ID3v2::TextIdentificationFrame *frame =
                    dynamic_cast< TagLib::ID3v2::TextIdentificationFrame * >( *it );

            if( !frame )
                continue;

            QString value = TStringToQString( frame->fieldList().toString( '\n' ) );

            if( field == Meta::valDiscNr )
            {
                int disc;
                if( ( disc = splitDiscNr( value ).first ) )
                    data.insert( field, disc );
            }
            else if( field == Meta::valBpm )
                data.insert( field, value.toFloat() );
            else
                data.insert( field, value );
        }
        else if( frameName == POPM_Frame )
        {
            TagLib::ID3v2::PopularimeterFrame *frame =
                    dynamic_cast< TagLib::ID3v2::PopularimeterFrame * >( *it );

            if( !frame )
                continue;

            if( TStringToQString( frame->email() ).isEmpty() ) // only read anonymous ratings
            {
                // FMPS tags have precedence
                if( !data.contains( Meta::valRating ) && frame->rating() != 0 )
                    data.insert( Meta::valRating, qRound( frame->rating() / 256.0 * 10.0 ) );
                if( !data.contains( Meta::valPlaycount ) && frame->counter() < 10000 )
                    data.insert( Meta::valPlaycount, frame->counter() );
            }
        }
        else if( frameName == TXXX_Frame )
        {
            TagLib::ID3v2::UserTextIdentificationFrame *frame =
                    dynamic_cast< TagLib::ID3v2::UserTextIdentificationFrame * >( *it );

            if( !frame )
                continue;

            // the value of the user text frame is stored in the
            // second and following fields.
            TagLib::StringList fields = frame->fieldList();
            if( fields.size() >= 2 )
            {
                QString value = TStringToQString( fields[1] );

                if( fields[0] == fmpsFieldName( FMPSRating ) )
                    data.insert( Meta::valRating, qRound( value.toFloat() * 10.0 ) );
                else if( fields[0] == fmpsFieldName( FMPSScore ) )
                    data.insert( Meta::valScore, value.toFloat() * 100.0 );
                else if( fields[0] == fmpsFieldName( FMPSPlayCount ) )
                    data.insert( Meta::valPlaycount, value.toFloat() );
            }
        }
    }

    return data;
}
bool
ID3v2TagHelper::setTags( const Meta::FieldHash &changes )
{
    bool modified = TagHelper::setTags( changes );

    foreach( const qint64 key, changes.keys() )
    {
        QVariant value = changes.value( key );
        TagLib::ByteVector field( fieldName( key ).toCString() );

        if( !field.isNull() && !field.isEmpty() )
        {
            if( key == Meta::valHasCover )
                continue;
            else if( key == Meta::valUniqueId )
            {
                QPair< UIDType, QString > uidPair = splitUID( value.toString() );
                if( uidPair.first == UIDInvalid )
                    continue;

                TagLib::String owner  = uidFieldName( uidPair.first );
                TagLib::ByteVector uid( uidPair.second.toAscii().data() );
                TagLib::ID3v2::FrameList list = m_tag->frameList();

                for( TagLib::ID3v2::FrameList::ConstIterator it = list.begin(); it != list.end(); ++it )
                {
                    if( ( *it )->frameID() == field )
                    {
                        TagLib::ID3v2::UniqueFileIdentifierFrame *frame =
                                dynamic_cast< TagLib::ID3v2::UniqueFileIdentifierFrame * >( *it );
                        if( !frame )
                            continue;

                        if( frame->owner() == owner )
                        {
                            m_tag->removeFrame( frame );
                            modified = true;
                            break;
                        }
                    }
                }

                if ( !uid.isEmpty() )
                {
                    m_tag->addFrame( new TagLib::ID3v2::UniqueFileIdentifierFrame( owner, uid ) );
                    modified = true;
                }
                continue;
            }

            TagLib::String tValue = Qt4QStringToTString( ( key == Meta::valCompilation )
                                                         ? QString::number( value.toInt() )
                                                         : value.toString() );
            if( tValue.isEmpty() )
                m_tag->removeFrames( field );
            else
            {
                TagLib::ID3v2::TextIdentificationFrame *frame = NULL;
                if( !m_tag->frameListMap()[field].isEmpty() )
                    frame = dynamic_cast< TagLib::ID3v2::TextIdentificationFrame * >(
                                                  m_tag->frameListMap()[field].front()
                                                                                    );
                if( !frame )
                {
                    frame = new TagLib::ID3v2::TextIdentificationFrame( field );
                    m_tag->addFrame( frame );
                }
                // note: TagLib is smart enough to automatically set UTF8 encoding if needed.
                frame->setText( tValue );
            }
            modified = true;
        }
        else if( key == Meta::valScore || key == Meta::valRating || key == Meta::valPlaycount )
        {
            TagLib::String description;
            TagLib::String tValue;

            if( key == Meta::valRating )
            {
                description = fmpsFieldName( FMPSRating );
                tValue = Qt4QStringToTString( QString::number( value.toFloat() / 10.0 ) );
            }
            else if( key == Meta::valScore )
            {
                description = fmpsFieldName( FMPSScore );
                tValue = Qt4QStringToTString( QString::number( value.toFloat() / 100.0 ) );
            }
            else if( key == Meta::valPlaycount )
            {
                description = fmpsFieldName( FMPSPlayCount );
                tValue = Qt4QStringToTString( QString::number( value.toInt() ) );
            }

            if( key == Meta::valRating || key == Meta::valPlaycount )
            {
                TagLib::ID3v2::PopularimeterFrame *popFrame = NULL;
                if( !m_tag->frameListMap()[POPM_Frame].isEmpty() )
                    popFrame = dynamic_cast< TagLib::ID3v2::PopularimeterFrame * >( m_tag->frameListMap()[POPM_Frame].front() );

                if( !popFrame )
                {
                    popFrame = new TagLib::ID3v2::PopularimeterFrame( POPM_Frame );
                    m_tag->addFrame( popFrame );
                }

                if( key == Meta::valRating )
                    popFrame->setRating( qBound(0, int(qRound(value.toDouble() / 10.0 * 256)), 255) );
                else
                    popFrame->setCounter( value.toInt() );

                modified = true;
            }

            TagLib::ID3v2::FrameList list = m_tag->frameList();
            for( TagLib::ID3v2::FrameList::ConstIterator it = list.begin(); it != list.end(); ++it )
            {
                if( ( *it )->frameID() == TXXX_Frame )
                {
                    TagLib::ID3v2::UserTextIdentificationFrame *frame =
                            dynamic_cast< TagLib::ID3v2::UserTextIdentificationFrame * >( *it );
                    if( !frame )
                        continue;

                    if( frame->description() == description )
                    {
                        m_tag->removeFrame( frame );
                        modified = true;
                        break;
                    }
                }
            }

            if( value.toBool() )
            {
                TagLib::ID3v2::UserTextIdentificationFrame *frame =
                        new TagLib::ID3v2::UserTextIdentificationFrame( TXXX_Frame );

                frame->setDescription( description );
                frame->setText( tValue );
                m_tag->addFrame( frame );
                modified = true;
            }
        }
    }

    return modified;
}