Commit d88c0e23 authored by Urs Fleisch's avatar Urs Fleisch
Browse files

improved display and editing of PRIV, UFID, MCDI and POPM frames

parent 6c1d07f0
......@@ -4,7 +4,7 @@ if (HAVE_TAGLIB)
set(TAGLIBEXT_LIBRARIES taglibext)
endif (HAVE_TAGLIB)
set(kid3_SRCS filelist.cpp filelistitem.cpp frame.cpp framelist.cpp frametable.cpp genres.cpp id3form.cpp kid3.cpp main.cpp m4afile.cpp mp3file.cpp configdialog.cpp exportdialog.cpp formatconfig.cpp formatbox.cpp importdialog.cpp importselector.cpp importparser.cpp generalconfig.cpp importconfig.cpp miscconfig.cpp freedbdialog.cpp freedbconfig.cpp freedbclient.cpp rendirdialog.cpp dirlist.cpp taggedfile.cpp musicbrainzdialog.cpp musicbrainzconfig.cpp musicbrainzclient.cpp numbertracksdialog.cpp oggfile.cpp vcedit.c flacfile.cpp commandstable.cpp taglibfile.cpp importsourceconfig.cpp importsourcedialog.cpp importsourceclient.cpp discogsdialog.cpp discogsclient.cpp discogsconfig.cpp musicbrainzreleasedialog.cpp musicbrainzreleaseclient.cpp externalprocess.cpp importtrackdata.cpp stringlistedit.cpp tracktypedialog.cpp tracktypeclient.cpp filterconfig.cpp filterdialog.cpp filefilter.cpp expressionparser.cpp pictureframe.cpp formatreplacer.cpp httpclient.cpp downloaddialog.cpp picturelabel.cpp browsecoverartdialog.cpp configtable.cpp)
set(kid3_SRCS filelist.cpp filelistitem.cpp frame.cpp framelist.cpp frametable.cpp genres.cpp id3form.cpp kid3.cpp main.cpp m4afile.cpp mp3file.cpp configdialog.cpp exportdialog.cpp formatconfig.cpp formatbox.cpp importdialog.cpp importselector.cpp importparser.cpp generalconfig.cpp importconfig.cpp miscconfig.cpp freedbdialog.cpp freedbconfig.cpp freedbclient.cpp rendirdialog.cpp dirlist.cpp taggedfile.cpp musicbrainzdialog.cpp musicbrainzconfig.cpp musicbrainzclient.cpp numbertracksdialog.cpp oggfile.cpp vcedit.c flacfile.cpp commandstable.cpp taglibfile.cpp importsourceconfig.cpp importsourcedialog.cpp importsourceclient.cpp discogsdialog.cpp discogsclient.cpp discogsconfig.cpp musicbrainzreleasedialog.cpp musicbrainzreleaseclient.cpp externalprocess.cpp importtrackdata.cpp stringlistedit.cpp tracktypedialog.cpp tracktypeclient.cpp filterconfig.cpp filterdialog.cpp filefilter.cpp expressionparser.cpp pictureframe.cpp formatreplacer.cpp httpclient.cpp downloaddialog.cpp picturelabel.cpp browsecoverartdialog.cpp configtable.cpp attributedata.cpp)
if (HAVE_QTDBUS)
set(kid3_SRCS ${kid3_SRCS} scriptinterface.cpp)
......
......@@ -28,14 +28,14 @@ kid3_LDADD += taglibext/libtaglibext.la
endif
# which sources should be compiled for kid3
kid3_SOURCES = filelist.cpp filelistitem.cpp frame.cpp framelist.cpp frametable.cpp genres.cpp id3form.cpp kid3.cpp main.cpp m4afile.cpp mp3file.cpp configdialog.cpp exportdialog.cpp formatconfig.cpp formatbox.cpp importdialog.cpp importselector.cpp importparser.cpp generalconfig.cpp importconfig.cpp miscconfig.cpp freedbdialog.cpp freedbconfig.cpp freedbclient.cpp rendirdialog.cpp dirlist.cpp taggedfile.cpp musicbrainzdialog.cpp musicbrainzconfig.cpp musicbrainzclient.cpp numbertracksdialog.cpp oggfile.cpp vcedit.c flacfile.cpp commandstable.cpp taglibfile.cpp importsourceconfig.cpp importsourcedialog.cpp importsourceclient.cpp discogsdialog.cpp discogsclient.cpp discogsconfig.cpp musicbrainzreleasedialog.cpp musicbrainzreleaseclient.cpp externalprocess.cpp importtrackdata.cpp stringlistedit.cpp tracktypedialog.cpp tracktypeclient.cpp scriptinterface.cpp filterconfig.cpp filterdialog.cpp filefilter.cpp expressionparser.cpp pictureframe.cpp formatreplacer.cpp httpclient.cpp downloaddialog.cpp picturelabel.cpp browsecoverartdialog.cpp configtable.cpp
kid3_SOURCES = filelist.cpp filelistitem.cpp frame.cpp framelist.cpp frametable.cpp genres.cpp id3form.cpp kid3.cpp main.cpp m4afile.cpp mp3file.cpp configdialog.cpp exportdialog.cpp formatconfig.cpp formatbox.cpp importdialog.cpp importselector.cpp importparser.cpp generalconfig.cpp importconfig.cpp miscconfig.cpp freedbdialog.cpp freedbconfig.cpp freedbclient.cpp rendirdialog.cpp dirlist.cpp taggedfile.cpp musicbrainzdialog.cpp musicbrainzconfig.cpp musicbrainzclient.cpp numbertracksdialog.cpp oggfile.cpp vcedit.c flacfile.cpp commandstable.cpp taglibfile.cpp importsourceconfig.cpp importsourcedialog.cpp importsourceclient.cpp discogsdialog.cpp discogsclient.cpp discogsconfig.cpp musicbrainzreleasedialog.cpp musicbrainzreleaseclient.cpp externalprocess.cpp importtrackdata.cpp stringlistedit.cpp tracktypedialog.cpp tracktypeclient.cpp scriptinterface.cpp filterconfig.cpp filterdialog.cpp filefilter.cpp expressionparser.cpp pictureframe.cpp formatreplacer.cpp httpclient.cpp downloaddialog.cpp picturelabel.cpp browsecoverartdialog.cpp configtable.cpp attributedata.cpp
# these headers are automatically built
BUILT_SOURCES =
CLEANFILES = allsys.h allsys.h.gch
# these are the headers for your project that won't be installed
noinst_HEADERS = configdialog.h exportdialog.h filelist.h filelistitem.h formatbox.h formatconfig.h frame.h framelist.h frametable.h freedbclient.h freedbconfig.h freedbdialog.h generalconfig.h genres.h id3form.h importconfig.h importdialog.h importparser.h importselector.h kid3.h miscconfig.h m4afile.h mp3file.h rendirdialog.h dirlist.h taggedfile.h musicbrainzclient.h musicbrainzconfig.h musicbrainzdialog.h numbertracksdialog.h oggfile.hpp vcedit.h flacfile.hpp commandstable.h taglibfile.h importsourceconfig.h importsourcedialog.h importsourceclient.h discogsdialog.h discogsclient.h discogsconfig.h musicbrainzreleasedialog.h musicbrainzreleaseclient.h qtcompatmac.h dirinfo.h externalprocess.h stringlistedit.h tracktypedialog.h tracktypeclient.h scriptinterface.h filterconfig.h filterdialog.h filefilter.h expressionparser.h pictureframe.h formatreplacer.h httpclient.h downloaddialog.h picturelabel.h browsecoverartdialog.h configtable.h
noinst_HEADERS = configdialog.h exportdialog.h filelist.h filelistitem.h formatbox.h formatconfig.h frame.h framelist.h frametable.h freedbclient.h freedbconfig.h freedbdialog.h generalconfig.h genres.h id3form.h importconfig.h importdialog.h importparser.h importselector.h kid3.h miscconfig.h m4afile.h mp3file.h rendirdialog.h dirlist.h taggedfile.h musicbrainzclient.h musicbrainzconfig.h musicbrainzdialog.h numbertracksdialog.h oggfile.hpp vcedit.h flacfile.hpp commandstable.h taglibfile.h importsourceconfig.h importsourcedialog.h importsourceclient.h discogsdialog.h discogsclient.h discogsconfig.h musicbrainzreleasedialog.h musicbrainzreleaseclient.h qtcompatmac.h dirinfo.h externalprocess.h stringlistedit.h tracktypedialog.h tracktypeclient.h scriptinterface.h filterconfig.h filterdialog.h filefilter.h expressionparser.h pictureframe.h formatreplacer.h httpclient.h downloaddialog.h picturelabel.h browsecoverartdialog.h configtable.h attributedata.h
# additional files in distribution
EXTRA_DIST = kid3.desktop kid3ui.rc hi16-app-kid3.png hi32-app-kid3.png hi48-app-kid3.png hisc-app-kid3.svgz de_qt.po ru_qt.po es_qt.po fr_qt.po
......
/**
* \file attributedata.cpp
* String representation of attribute data.
*
* \b Project: Kid3
* \author Urs Fleisch
* \date 28 Mar 2009
*
* Copyright (C) 2009 Urs Fleisch
*
* This file is part of Kid3.
*
* Kid3 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Kid3 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "attributedata.h"
#include <qmap.h>
#include "qtcompatmac.h"
/**
* Constructor.
*
* @param name owner of Windows media PRIV frame
*/
AttributeData::AttributeData(const QString& name)
{
/** PRIV-owner and type of Windows media PRIV frames */
static const struct TypeOfWmPriv {
const char* str;
Type type;
} typeOfWmPriv[] = {
{ "AverageLevel", DWord },
{ "PeakValue", DWord },
{ "WM/AlbumArtist", Utf16 },
{ "WM/AuthorURL", Utf16 },
{ "WM/BeatsPerMinute", Utf16 },
{ "WM/Composer", Utf16 },
{ "WM/Conductor", Utf16 },
{ "WM/ContentDistributor", Utf16 },
{ "WM/ContentGroupDescription", Utf16 },
{ "WM/EncodedBy", Utf16 },
{ "WM/EncodingSettings", Utf16 },
{ "WM/EncodingTime", Binary },
{ "WM/Genre", Utf16 },
{ "WM/InitialKey", Utf16 },
{ "WM/Language", Utf16 },
{ "WM/Lyrics", Utf16 },
{ "WM/Lyrics_Synchronised", Binary },
{ "WM/MCDI", Binary },
{ "WM/MediaClassPrimaryID", Guid },
{ "WM/MediaClassSecondaryID", Guid },
{ "WM/Mood", Utf16 },
{ "WM/ParentalRating", Utf16 },
{ "WM/PartOfSet", Utf16 },
{ "WM/Period", Utf16 },
{ "WM/Picture", Binary },
{ "WM/Producer", Utf16 },
{ "WM/PromotionURL", Utf16 },
{ "WM/Provider", Utf16 },
{ "WM/Publisher", Utf16 },
{ "WM/SubTitle", Utf16 },
{ "WM/ToolName", Utf16 },
{ "WM/ToolVersion", Utf16 },
{ "WM/TrackNumber", Utf16 },
{ "WM/UniqueFileIdentifier", Utf16 },
{ "WM/UserWebURL", Binary },
{ "WM/WMCollectionGroupID", Guid },
{ "WM/WMCollectionID", Guid },
{ "WM/WMContentID", Guid },
{ "WM/Writer", Utf16 }
};
static QMap<QString, int> strNumMap;
if (strNumMap.empty()) {
// first time initialization
for (unsigned i = 0; i < sizeof(typeOfWmPriv) / sizeof(typeOfWmPriv[0]);
++i) {
strNumMap.insert(QString(typeOfWmPriv[i].str), typeOfWmPriv[i].type);
}
}
QMap<QString, int>::const_iterator it =
strNumMap.find(name);
m_type = (it != strNumMap.end()) ? static_cast<Type>(*it) : Unknown;
}
/**
* Convert attribute data to string.
*
* @param data byte array with data
* @param str result string
*
* @return true if ok.
*/
bool AttributeData::toString(const QByteArray& data, QString& str)
{
switch (m_type) {
case Utf16: {
const ushort* unicode = reinterpret_cast<const ushort*>(data.data());
int size = data.size() / 2;
if (unicode[size - 1] == 0) {
--size;
}
#if QT_VERSION >= 0x040000
str = QString::fromUtf16(unicode, size);
#else
str.setUnicodeCodes(unicode, size);
#endif
return true;
}
case Guid:
if (data.size() == 16) {
#if QT_VERSION >= 0x040000
str.clear();
#else
str.truncate(0);
#endif
for (int i = 0; i < 16; ++i) {
if (i == 4 || i == 6 || i == 8 || i == 10) {
str += '-';
}
unsigned char c = (unsigned char)data[i];
unsigned char d = c >> 4;
str += d >= 10 ? d - 10 + 'A' : d + '0';
d = c & 0x0f;
str += d >= 10 ? d - 10 + 'A' : d + '0';
}
return true;
}
break;
case DWord:
if (data.size() == 4) {
ulong num = 0;
for (int i = 3; i >= 0; --i) {
num <<= 8;
num |= static_cast<unsigned char>(data[i]);
}
str.setNum(num);
return true;
}
break;
case Binary:
case Unknown:
default:
;
}
return false;
}
/**
* Convert attribute data string to byte array.
*
* @param str string representation of data
* @param data result data
*
* @return true if ok.
*/
bool AttributeData::toByteArray(const QString& str, QByteArray& data)
{
switch (m_type) {
case Utf16: {
#if QT_VERSION >= 0x040000
const ushort* unicode = str.utf16();
#else
const ushort* unicode = str.ucs2();
#endif
QCM_duplicate(data, reinterpret_cast<const char*>(unicode),
(str.length() + 1) * 2);
return true;
}
case Guid: {
QString hexStr(str.QCM_toUpper());
hexStr.remove('-');
if (hexStr.length() == 32) {
unsigned char buf[16];
unsigned char* bufPtr = buf;
for (int i = 0; i < 32;) {
#if QT_VERSION >= 0x040000
unsigned char h = (unsigned char)hexStr[i++].toLatin1();
unsigned char l = (unsigned char)hexStr[i++].toLatin1();
#else
unsigned char h = (unsigned char)hexStr[i++].latin1();
unsigned char l = (unsigned char)hexStr[i++].latin1();
#endif
if (!((h >= '0' && h <= '9') || (h >= 'A' && h <= 'F')) ||
!((l >= '0' && l <= '9') || (l >= 'A' && l <= 'F'))) {
return false;
}
*bufPtr++ = ((h >= 'A' ? h + 10 - 'A' : h - '0') << 4) |
(l >= 'A' ? l + 10 - 'A' : l - '0');
}
QCM_duplicate(data, reinterpret_cast<char*>(buf), 16);
return true;
}
break;
}
case DWord: {
bool ok;
ulong num = str.toULong(&ok);
if (ok) {
data.resize(4);
for (int i = 0; i < 4; ++i) {
data[i] = num & 0xff;
num >>= 8;
}
return true;
}
break;
}
case Binary:
case Unknown:
default:
;
}
return false;
}
/**
* Check if a string represents a hexadecimal number, i.e.
* contains only characters 0..9, A..F.
*
* @param str string to check
* @param lastAllowedLetter last allowed character (normally 'F')
* @param additionalChars additional allowed characters
*
* @return true if string has hex format.
*/
bool AttributeData::isHexString(const QString& str, char lastAllowedLetter,
const QString additionalChars)
{
if (str.isEmpty()) {
return false;
}
for (int i = 0; i < static_cast<int>(str.length()); ++i) {
#if QT_VERSION >= 0x040000
char c = str[i].toLatin1();
#else
char c = str[i].latin1();
#endif
if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= lastAllowedLetter) ||
additionalChars.QCM_indexOf(c) != -1)) {
return false;
}
}
return true;
}
/**
* \file attributedata.h
* String representation of attribute data.
*
* \b Project: Kid3
* \author Urs Fleisch
* \date 28 Mar 2009
*
* Copyright (C) 2009 Urs Fleisch
*
* This file is part of Kid3.
*
* Kid3 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Kid3 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ATTRIBUTEDATA_H
#define ATTRIBUTEDATA_H
#include <qstring.h>
#if QT_VERSION >= 0x040000
#include <QByteArray>
#endif
/** Attribute data used e.g. by Windows Media Player. */
class AttributeData {
public:
/** Attribute data types. */
enum Type {
Unknown, /**< Unknown type */
Utf16, /**< UTF-16 encoded, zero-terminated Unicode string */
Guid, /**< 128-bit GUID */
DWord, /**< 32-bit value little-endian */
Binary /**< Binary data */
};
/**
* Constructor.
*
* @param type type
*/
AttributeData(Type type)
{
m_type = type;
}
/**
* Constructor.
*
* @param name owner of Windows media PRIV frame
*/
AttributeData(const QString& name);
/**
* Destructor.
*/
~AttributeData() {}
/**
* Get type.
* @return type.
*/
Type getType() const { return m_type; }
/**
* Convert attribute data to string.
*
* @param data byte array with data
* @param str result string
*
* @return true if ok.
*/
bool toString(const QByteArray& data, QString& str);
/**
* Convert attribute data string to byte array.
*
* @param str string representation of data
* @param data result data
*
* @return true if ok.
*/
bool toByteArray(const QString& str, QByteArray& data);
/**
* Check if a string represents a hexadecimal number, i.e.
* contains only characters 0..9, A..F.
*
* @param str string to check
* @param lastAllowedLetter last allowed character (normally 'F')
* @param additionalChars additional allowed characters
*
* @return true if string has hex format.
*/
static bool isHexString(const QString& str, char lastAllowedLetter = 'F',
const QString additionalChars = QString());
private:
Type m_type;
};
#endif // ATTRIBUTEDATA_H
......@@ -210,6 +210,25 @@ int Frame::numberWithoutTotal(const QString& str, bool* ok)
str.left(slashPos).toInt(ok);
}
/**
* Get the value of a field.
*
* @param id field ID
*
* @return field value, invalid if field not found.
*/
QVariant Frame::getFieldValue(Field::Id id) const
{
for (FieldList::const_iterator it = m_fieldList.begin();
it != m_fieldList.end();
++it) {
if ((*it).m_id == id) {
return (*it).m_value;
}
}
return QVariant();
}
/**
* Set values which are different inactive.
......
......@@ -269,6 +269,15 @@ public:
*/
FieldList& fieldList() { return m_fieldList; }
/**
* Get the value of a field.
*
* @param id field ID
*
* @return field value, invalid if field not found.
*/
QVariant getFieldValue(Field::Id id) const;
/**
* Get name of frame from type.
*
......
......@@ -49,9 +49,9 @@ contains(CFG_LIBS, -ltag) {
POST_TARGETDEPS += $$TAGLIBEXT_LIB
}
SOURCES = filelist.cpp filelistitem.cpp framelist.cpp frame.cpp frametable.cpp genres.cpp id3form.cpp kid3.cpp main.cpp m4afile.cpp mp3file.cpp configdialog.cpp exportdialog.cpp formatconfig.cpp formatbox.cpp importdialog.cpp importselector.cpp importparser.cpp generalconfig.cpp importconfig.cpp miscconfig.cpp freedbdialog.cpp freedbconfig.cpp freedbclient.cpp rendirdialog.cpp dirlist.cpp taggedfile.cpp musicbrainzdialog.cpp musicbrainzconfig.cpp musicbrainzclient.cpp numbertracksdialog.cpp oggfile.cpp vcedit.c flacfile.cpp commandstable.cpp taglibfile.cpp importsourceconfig.cpp importsourcedialog.cpp importsourceclient.cpp discogsdialog.cpp discogsclient.cpp discogsconfig.cpp musicbrainzreleasedialog.cpp musicbrainzreleaseclient.cpp externalprocess.cpp importtrackdata.cpp stringlistedit.cpp tracktypedialog.cpp tracktypeclient.cpp filterconfig.cpp filterdialog.cpp filefilter.cpp expressionparser.cpp pictureframe.cpp formatreplacer.cpp httpclient.cpp downloaddialog.cpp picturelabel.cpp browsecoverartdialog.cpp configtable.cpp
SOURCES = filelist.cpp filelistitem.cpp framelist.cpp frame.cpp frametable.cpp genres.cpp id3form.cpp kid3.cpp main.cpp m4afile.cpp mp3file.cpp configdialog.cpp exportdialog.cpp formatconfig.cpp formatbox.cpp importdialog.cpp importselector.cpp importparser.cpp generalconfig.cpp importconfig.cpp miscconfig.cpp freedbdialog.cpp freedbconfig.cpp freedbclient.cpp rendirdialog.cpp dirlist.cpp taggedfile.cpp musicbrainzdialog.cpp musicbrainzconfig.cpp musicbrainzclient.cpp numbertracksdialog.cpp oggfile.cpp vcedit.c flacfile.cpp commandstable.cpp taglibfile.cpp importsourceconfig.cpp importsourcedialog.cpp importsourceclient.cpp discogsdialog.cpp discogsclient.cpp discogsconfig.cpp musicbrainzreleasedialog.cpp musicbrainzreleaseclient.cpp externalprocess.cpp importtrackdata.cpp stringlistedit.cpp tracktypedialog.cpp tracktypeclient.cpp filterconfig.cpp filterdialog.cpp filefilter.cpp expressionparser.cpp pictureframe.cpp formatreplacer.cpp httpclient.cpp downloaddialog.cpp picturelabel.cpp browsecoverartdialog.cpp configtable.cpp attributedata.cpp
HEADERS = configdialog.h exportdialog.h filelist.h filelistitem.h formatbox.h formatconfig.h frame.h framelist.h frametable.h freedbclient.h freedbconfig.h freedbdialog.h generalconfig.h genres.h id3form.h importconfig.h importdialog.h importparser.h importselector.h kid3.h miscconfig.h m4afile.h mp3file.h rendirdialog.h dirlist.h taggedfile.h musicbrainzclient.h musicbrainzconfig.h musicbrainzdialog.h numbertracksdialog.h oggfile.hpp vcedit.h flacfile.hpp commandstable.h taglibfile.h importsourceconfig.h importsourcedialog.h importsourceclient.h discogsdialog.h discogsclient.h discogsconfig.h musicbrainzreleasedialog.h musicbrainzreleaseclient.h qtcompatmac.h dirinfo.h externalprocess.h stringlistedit.h tracktypedialog.h tracktypeclient.h filterconfig.h filterdialog.h filefilter.h expressionparser.h pictureframe.h formatreplacer.h httpclient.h downloaddialog.h picturelabel.h browsecoverartdialog.h configtable.h
HEADERS = configdialog.h exportdialog.h filelist.h filelistitem.h formatbox.h formatconfig.h frame.h framelist.h frametable.h freedbclient.h freedbconfig.h freedbdialog.h generalconfig.h genres.h id3form.h importconfig.h importdialog.h importparser.h importselector.h kid3.h miscconfig.h m4afile.h mp3file.h rendirdialog.h dirlist.h taggedfile.h musicbrainzclient.h musicbrainzconfig.h musicbrainzdialog.h numbertracksdialog.h oggfile.hpp vcedit.h flacfile.hpp commandstable.h taglibfile.h importsourceconfig.h importsourcedialog.h importsourceclient.h discogsdialog.h discogsclient.h discogsconfig.h musicbrainzreleasedialog.h musicbrainzreleaseclient.h qtcompatmac.h dirinfo.h externalprocess.h stringlistedit.h tracktypedialog.h tracktypeclient.h filterconfig.h filterdialog.h filefilter.h expressionparser.h pictureframe.h formatreplacer.h httpclient.h downloaddialog.h picturelabel.h browsecoverartdialog.h configtable.h attributedata.h
unix:program.path = $$CFG_BINDIR $$CFG_DATAROOTDIR/applications $$CFG_DATAROOTDIR/icons/hicolor/16x16/apps $$CFG_DATAROOTDIR/icons/hicolor/32x32/apps $$CFG_DATAROOTDIR/icons/hicolor/48x48/apps $$CFG_DATAROOTDIR/icons/hicolor/scalable/apps
win32 {
......
......@@ -43,6 +43,7 @@
#include "genres.h"
#include "dirinfo.h"
#include "kid3.h"
#include "attributedata.h"
#include <cstring>
#include <sys/stat.h>
#ifdef WIN32
......@@ -1641,6 +1642,64 @@ bool Mp3File::setFrameV2(const Frame& frame)
markTag2Changed(frame.getType());
}
return true;
} else if (id3Frame->GetID() == ID3FID_PRIVATE &&
(fld = id3Frame->GetField(ID3FN_DATA)) != 0) {
ID3_Field* ownerFld = id3Frame->GetField(ID3FN_OWNER);
QString owner;
QByteArray newData, oldData;
if (ownerFld && !(owner = getString(ownerFld)).isEmpty() &&
AttributeData(owner).toByteArray(value, newData)) {
QCM_duplicate(oldData,
(const char *)fld->GetRawBinary(),
(unsigned int)fld->Size());
if (newData != oldData) {
fld->Set(reinterpret_cast<const unsigned char*>(newData.data()),
newData.size());
markTag2Changed(frame.getType());
}
return true;
}
} else if (id3Frame->GetID() == ID3FID_CDID &&
(fld = id3Frame->GetField(ID3FN_DATA)) != 0) {
QByteArray newData, oldData;
if (AttributeData::isHexString(value, 'F', "+") &&
AttributeData(AttributeData::Utf16).toByteArray(value, newData)) {
QCM_duplicate(oldData,
(const char *)fld->GetRawBinary(),
(unsigned int)fld->Size());
if (newData != oldData) {
fld->Set(reinterpret_cast<const unsigned char*>(newData.data()),
newData.size());
markTag2Changed(frame.getType());
}
return true;
}
} else if (id3Frame->GetID() == ID3FID_UNIQUEFILEID &&
(fld = id3Frame->GetField(ID3FN_DATA)) != 0) {
QByteArray newData, oldData;
if (AttributeData::isHexString(value, 'Z')) {
#if QT_VERSION >= 0x040000
newData = (value + '\0').toLatin1();
#else
newData.duplicate((value + '\0').latin1(), value.length() + 1);
#endif
QCM_duplicate(oldData,
(const char *)fld->GetRawBinary(),
(unsigned int)fld->Size());
if (newData != oldData) {
fld->Set(reinterpret_cast<const unsigned char*>(newData.data()),
newData.size());
markTag2Changed(frame.getType());
}
return true;
}
} else if (id3Frame->GetID() == ID3FID_POPULARIMETER &&
(fld = id3Frame->GetField(ID3FN_RATING)) != 0) {
if (getString(fld) != value) {
fld->Set(value.toInt());
markTag2Changed(frame.getType());
}
return true;
}
} else {
setId3v2Frame(id3Frame, frame);
......@@ -1812,17 +1871,61 @@ void Mp3File::getAllFramesV2(FrameCollection& frames)
if (id3Frame->GetID() == ID3FID_USERTEXT ||
id3Frame->GetID() == ID3FID_WWWUSER ||
id3Frame->GetID() == ID3FID_COMMENT) {
QVariant fieldValue = frame.getFieldValue(Frame::Field::ID_Description);
if (fieldValue.isValid()) {
QString description = fieldValue.toString();
if (!description.isEmpty()) {
frame.setInternalName(QString(name) + '\n' + description);
frame.setType(Frame::FT_Other);
}
}
} else if (id3Frame->GetID() == ID3FID_PRIVATE) {
const Frame::FieldList& fields = frame.getFieldList();
QString owner;
QByteArray data;
for (Frame::FieldList::const_iterator it = fields.begin();
it != fields.end();
++it) {
if ((*it).m_id == Frame::Field::ID_Description) {
QString description = (*it).m_value.toString();
if (!description.isEmpty()) {
frame.setInternalName(QString(name) + '\n' + description);
frame.setType(Frame::FT_Other);
it != fields.end();
++it) {
if ((*it).m_id == Frame::Field::ID_Owner) {
owner = (*it).m_value.toString();
if (!owner.isEmpty()) {
frame.setInternalName(QString(name) + '\n' + owner);
}
break;
} else if ((*it).m_id == Frame::Field::ID_Data) {
data = (*it).m_value.toByteArray();
}
}
if (!owner.isEmpty() && !data.isEmpty()) {
QString str;
if (AttributeData(owner).toString(data, str)) {
frame.setValue(str);
}
}
} else if (id3Frame->GetID() == ID3FID_CDID) {
QVariant fieldValue = frame.getFieldValue(Frame::Field::ID_Data);
if (fieldValue.isValid()) {
QString str;
if (AttributeData(AttributeData::Utf16).toString(fieldValue.toByteArray(), str) &&
AttributeData::isHexString(str, 'F', "+")) {
frame.setValue(str);
}
}
} else if (id3Frame->GetID() == ID3FID_UNIQUEFILEID) {
QVariant fieldValue = frame.getFieldValue(Frame::Field::ID_Data);
if (fieldValue.isValid()) {
QByteArray ba(fieldValue.toByteArray());
QString str(ba);
if (ba.size() - str.length() <= 1 &&
AttributeData::isHexString(str, 'Z')) {
frame.setValue(str);
}
}
} else if (id3Frame->GetID() == ID3FID_POPULARIMETER) {
QVariant fieldValue = frame.getFieldValue(Frame::Field::ID_Rating);
if (fieldValue.isValid()) {
QString str(fieldValue.toString());
if (!str.isEmpty()) {
frame.setValue(str);
}
}
}
......