Format taglib sources

This commit is contained in:
Jonas Kvinge
2020-06-13 19:02:42 +02:00
parent 72bff7fa35
commit 4ce099294c
224 changed files with 12905 additions and 15623 deletions

View File

@@ -27,237 +27,232 @@
using namespace Strawberry_TagLib::TagLib;
namespace
{
const wchar_t *genres[] = {
L"Blues",
L"Classic Rock",
L"Country",
L"Dance",
L"Disco",
L"Funk",
L"Grunge",
L"Hip-Hop",
L"Jazz",
L"Metal",
L"New Age",
L"Oldies",
L"Other",
L"Pop",
L"R&B",
L"Rap",
L"Reggae",
L"Rock",
L"Techno",
L"Industrial",
L"Alternative",
L"Ska",
L"Death Metal",
L"Pranks",
L"Soundtrack",
L"Euro-Techno",
L"Ambient",
L"Trip-Hop",
L"Vocal",
L"Jazz+Funk",
L"Fusion",
L"Trance",
L"Classical",
L"Instrumental",
L"Acid",
L"House",
L"Game",
L"Sound Clip",
L"Gospel",
L"Noise",
L"Alternative Rock",
L"Bass",
L"Soul",
L"Punk",
L"Space",
L"Meditative",
L"Instrumental Pop",
L"Instrumental Rock",
L"Ethnic",
L"Gothic",
L"Darkwave",
L"Techno-Industrial",
L"Electronic",
L"Pop-Folk",
L"Eurodance",
L"Dream",
L"Southern Rock",
L"Comedy",
L"Cult",
L"Gangsta",
L"Top 40",
L"Christian Rap",
L"Pop/Funk",
L"Jungle",
L"Native American",
L"Cabaret",
L"New Wave",
L"Psychedelic",
L"Rave",
L"Showtunes",
L"Trailer",
L"Lo-Fi",
L"Tribal",
L"Acid Punk",
L"Acid Jazz",
L"Polka",
L"Retro",
L"Musical",
L"Rock & Roll",
L"Hard Rock",
L"Folk",
L"Folk/Rock",
L"National Folk",
L"Swing",
L"Fusion",
L"Bebob",
L"Latin",
L"Revival",
L"Celtic",
L"Bluegrass",
L"Avantgarde",
L"Gothic Rock",
L"Progressive Rock",
L"Psychedelic Rock",
L"Symphonic Rock",
L"Slow Rock",
L"Big Band",
L"Chorus",
L"Easy Listening",
L"Acoustic",
L"Humour",
L"Speech",
L"Chanson",
L"Opera",
L"Chamber Music",
L"Sonata",
L"Symphony",
L"Booty Bass",
L"Primus",
L"Porn Groove",
L"Satire",
L"Slow Jam",
L"Club",
L"Tango",
L"Samba",
L"Folklore",
L"Ballad",
L"Power Ballad",
L"Rhythmic Soul",
L"Freestyle",
L"Duet",
L"Punk Rock",
L"Drum Solo",
L"A Cappella",
L"Euro-House",
L"Dance Hall",
L"Goa",
L"Drum & Bass",
L"Club-House",
L"Hardcore",
L"Terror",
L"Indie",
L"BritPop",
L"Negerpunk",
L"Polsk Punk",
L"Beat",
L"Christian Gangsta Rap",
L"Heavy Metal",
L"Black Metal",
L"Crossover",
L"Contemporary Christian",
L"Christian Rock",
L"Merengue",
L"Salsa",
L"Thrash Metal",
L"Anime",
L"Jpop",
L"Synthpop",
L"Abstract",
L"Art Rock",
L"Baroque",
L"Bhangra",
L"Big Beat",
L"Breakbeat",
L"Chillout",
L"Downtempo",
L"Dub",
L"EBM",
L"Eclectic",
L"Electro",
L"Electroclash",
L"Emo",
L"Experimental",
L"Garage",
L"Global",
L"IDM",
L"Illbient",
L"Industro-Goth",
L"Jam Band",
L"Krautrock",
L"Leftfield",
L"Lounge",
L"Math Rock",
L"New Romantic",
L"Nu-Breakz",
L"Post-Punk",
L"Post-Rock",
L"Psytrance",
L"Shoegaze",
L"Space Rock",
L"Trop Rock",
L"World Music",
L"Neoclassical",
L"Audiobook",
L"Audio Theatre",
L"Neue Deutsche Welle",
L"Podcast",
L"Indie Rock",
L"G-Funk",
L"Dubstep",
L"Garage Rock",
L"Psybient"
};
const int genresSize = sizeof(genres) / sizeof(genres[0]);
}
namespace {
const wchar_t *genres[] = {
L"Blues",
L"Classic Rock",
L"Country",
L"Dance",
L"Disco",
L"Funk",
L"Grunge",
L"Hip-Hop",
L"Jazz",
L"Metal",
L"New Age",
L"Oldies",
L"Other",
L"Pop",
L"R&B",
L"Rap",
L"Reggae",
L"Rock",
L"Techno",
L"Industrial",
L"Alternative",
L"Ska",
L"Death Metal",
L"Pranks",
L"Soundtrack",
L"Euro-Techno",
L"Ambient",
L"Trip-Hop",
L"Vocal",
L"Jazz+Funk",
L"Fusion",
L"Trance",
L"Classical",
L"Instrumental",
L"Acid",
L"House",
L"Game",
L"Sound Clip",
L"Gospel",
L"Noise",
L"Alternative Rock",
L"Bass",
L"Soul",
L"Punk",
L"Space",
L"Meditative",
L"Instrumental Pop",
L"Instrumental Rock",
L"Ethnic",
L"Gothic",
L"Darkwave",
L"Techno-Industrial",
L"Electronic",
L"Pop-Folk",
L"Eurodance",
L"Dream",
L"Southern Rock",
L"Comedy",
L"Cult",
L"Gangsta",
L"Top 40",
L"Christian Rap",
L"Pop/Funk",
L"Jungle",
L"Native American",
L"Cabaret",
L"New Wave",
L"Psychedelic",
L"Rave",
L"Showtunes",
L"Trailer",
L"Lo-Fi",
L"Tribal",
L"Acid Punk",
L"Acid Jazz",
L"Polka",
L"Retro",
L"Musical",
L"Rock & Roll",
L"Hard Rock",
L"Folk",
L"Folk/Rock",
L"National Folk",
L"Swing",
L"Fusion",
L"Bebob",
L"Latin",
L"Revival",
L"Celtic",
L"Bluegrass",
L"Avantgarde",
L"Gothic Rock",
L"Progressive Rock",
L"Psychedelic Rock",
L"Symphonic Rock",
L"Slow Rock",
L"Big Band",
L"Chorus",
L"Easy Listening",
L"Acoustic",
L"Humour",
L"Speech",
L"Chanson",
L"Opera",
L"Chamber Music",
L"Sonata",
L"Symphony",
L"Booty Bass",
L"Primus",
L"Porn Groove",
L"Satire",
L"Slow Jam",
L"Club",
L"Tango",
L"Samba",
L"Folklore",
L"Ballad",
L"Power Ballad",
L"Rhythmic Soul",
L"Freestyle",
L"Duet",
L"Punk Rock",
L"Drum Solo",
L"A Cappella",
L"Euro-House",
L"Dance Hall",
L"Goa",
L"Drum & Bass",
L"Club-House",
L"Hardcore",
L"Terror",
L"Indie",
L"BritPop",
L"Negerpunk",
L"Polsk Punk",
L"Beat",
L"Christian Gangsta Rap",
L"Heavy Metal",
L"Black Metal",
L"Crossover",
L"Contemporary Christian",
L"Christian Rock",
L"Merengue",
L"Salsa",
L"Thrash Metal",
L"Anime",
L"Jpop",
L"Synthpop",
L"Abstract",
L"Art Rock",
L"Baroque",
L"Bhangra",
L"Big Beat",
L"Breakbeat",
L"Chillout",
L"Downtempo",
L"Dub",
L"EBM",
L"Eclectic",
L"Electro",
L"Electroclash",
L"Emo",
L"Experimental",
L"Garage",
L"Global",
L"IDM",
L"Illbient",
L"Industro-Goth",
L"Jam Band",
L"Krautrock",
L"Leftfield",
L"Lounge",
L"Math Rock",
L"New Romantic",
L"Nu-Breakz",
L"Post-Punk",
L"Post-Rock",
L"Psytrance",
L"Shoegaze",
L"Space Rock",
L"Trop Rock",
L"World Music",
L"Neoclassical",
L"Audiobook",
L"Audio Theatre",
L"Neue Deutsche Welle",
L"Podcast",
L"Indie Rock",
L"G-Funk",
L"Dubstep",
L"Garage Rock",
L"Psybient"
};
const int genresSize = sizeof(genres) / sizeof(genres[0]);
} // namespace
StringList ID3v1::genreList()
{
StringList ID3v1::genreList() {
StringList l;
for(int i = 0; i < genresSize; i++) {
for (int i = 0; i < genresSize; i++) {
l.append(genres[i]);
}
return l;
}
ID3v1::GenreMap ID3v1::genreMap()
{
ID3v1::GenreMap ID3v1::genreMap() {
GenreMap m;
for(int i = 0; i < genresSize; i++) {
for (int i = 0; i < genresSize; i++) {
m.insert(genres[i], i);
}
return m;
}
String ID3v1::genre(int i)
{
if(i >= 0 && i < genresSize)
return String(genres[i]); // always make a copy
String ID3v1::genre(int i) {
if (i >= 0 && i < genresSize)
return String(genres[i]); // always make a copy
else
return String();
}
int ID3v1::genreIndex(const String &name)
{
for(int i = 0; i < genresSize; ++i) {
if(name == genres[i])
int ID3v1::genreIndex(const String &name) {
for (int i = 0; i < genresSize; ++i) {
if (name == genres[i])
return i;
}

View File

@@ -32,37 +32,37 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v1 {
namespace ID3v1 {
typedef Map<String, int> GenreMap;
typedef Map<String, int> GenreMap;
/*!
/*!
* Returns the list of canonical ID3v1 genre names in the order that they
* are listed in the standard.
*/
StringList TAGLIB_EXPORT genreList();
StringList TAGLIB_EXPORT genreList();
/*!
/*!
* A "reverse mapping" that goes from the canonical ID3v1 genre name to the
* respective genre number. genreMap()["Rock"] ==
*/
GenreMap TAGLIB_EXPORT genreMap();
GenreMap TAGLIB_EXPORT genreMap();
/*!
/*!
* Returns the name of the genre at \a index in the ID3v1 genre list. If
* \a index is out of range -- less than zero or greater than 191 -- a null
* string will be returned.
*/
String TAGLIB_EXPORT genre(int index);
String TAGLIB_EXPORT genre(int index);
/*!
/*!
* Returns the genre index for the (case sensitive) genre \a name. If the
* genre is not in the list 255 (which signifies an unknown genre in ID3v1)
* will be returned.
*/
int TAGLIB_EXPORT genreIndex(const String &name);
}
}
}
int TAGLIB_EXPORT genreIndex(const String &name);
} // namespace ID3v1
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -32,20 +32,17 @@
using namespace Strawberry_TagLib::TagLib;
using namespace ID3v1;
namespace
{
const ID3v1::StringHandler defaultStringHandler;
const ID3v1::StringHandler *stringHandler = &defaultStringHandler;
}
namespace {
const ID3v1::StringHandler defaultStringHandler;
const ID3v1::StringHandler *stringHandler = &defaultStringHandler;
} // namespace
class ID3v1::Tag::TagPrivate
{
public:
TagPrivate() :
file(0),
tagOffset(0),
track(0),
genre(255) {}
class ID3v1::Tag::TagPrivate {
public:
TagPrivate() : file(0),
tagOffset(0),
track(0),
genre(255) {}
File *file;
long tagOffset;
@@ -63,18 +60,15 @@ public:
// StringHandler implementation
////////////////////////////////////////////////////////////////////////////////
StringHandler::StringHandler()
{
StringHandler::StringHandler() {
}
String ID3v1::StringHandler::parse(const ByteVector &data) const
{
String ID3v1::StringHandler::parse(const ByteVector &data) const {
return String(data, String::Latin1).stripWhiteSpace();
}
ByteVector ID3v1::StringHandler::render(const String &s) const
{
if(s.isLatin1())
ByteVector ID3v1::StringHandler::render(const String &s) const {
if (s.isLatin1())
return s.data(String::Latin1);
else
return ByteVector();
@@ -84,29 +78,23 @@ ByteVector ID3v1::StringHandler::render(const String &s) const
// public methods
////////////////////////////////////////////////////////////////////////////////
ID3v1::Tag::Tag() :
Strawberry_TagLib::TagLib::Tag(),
d(new TagPrivate())
{
ID3v1::Tag::Tag() : Strawberry_TagLib::TagLib::Tag(),
d(new TagPrivate()) {
}
ID3v1::Tag::Tag(File *file, long tagOffset) :
Strawberry_TagLib::TagLib::Tag(),
d(new TagPrivate())
{
ID3v1::Tag::Tag(File *file, long tagOffset) : Strawberry_TagLib::TagLib::Tag(),
d(new TagPrivate()) {
d->file = file;
d->tagOffset = tagOffset;
read();
}
ID3v1::Tag::~Tag()
{
ID3v1::Tag::~Tag() {
delete d;
}
ByteVector ID3v1::Tag::render() const
{
ByteVector ID3v1::Tag::render() const {
ByteVector data;
data.append(fileIdentifier());
@@ -122,94 +110,76 @@ ByteVector ID3v1::Tag::render() const
return data;
}
ByteVector ID3v1::Tag::fileIdentifier()
{
ByteVector ID3v1::Tag::fileIdentifier() {
return ByteVector::fromCString("TAG");
}
String ID3v1::Tag::title() const
{
String ID3v1::Tag::title() const {
return d->title;
}
String ID3v1::Tag::artist() const
{
String ID3v1::Tag::artist() const {
return d->artist;
}
String ID3v1::Tag::album() const
{
String ID3v1::Tag::album() const {
return d->album;
}
String ID3v1::Tag::comment() const
{
String ID3v1::Tag::comment() const {
return d->comment;
}
String ID3v1::Tag::genre() const
{
String ID3v1::Tag::genre() const {
return ID3v1::genre(d->genre);
}
unsigned int ID3v1::Tag::year() const
{
unsigned int ID3v1::Tag::year() const {
return d->year.toInt();
}
unsigned int ID3v1::Tag::track() const
{
unsigned int ID3v1::Tag::track() const {
return d->track;
}
void ID3v1::Tag::setTitle(const String &s)
{
void ID3v1::Tag::setTitle(const String &s) {
d->title = s;
}
void ID3v1::Tag::setArtist(const String &s)
{
void ID3v1::Tag::setArtist(const String &s) {
d->artist = s;
}
void ID3v1::Tag::setAlbum(const String &s)
{
void ID3v1::Tag::setAlbum(const String &s) {
d->album = s;
}
void ID3v1::Tag::setComment(const String &s)
{
void ID3v1::Tag::setComment(const String &s) {
d->comment = s;
}
void ID3v1::Tag::setGenre(const String &s)
{
void ID3v1::Tag::setGenre(const String &s) {
d->genre = ID3v1::genreIndex(s);
}
void ID3v1::Tag::setYear(unsigned int i)
{
void ID3v1::Tag::setYear(unsigned int i) {
d->year = i > 0 ? String::number(i) : String();
}
void ID3v1::Tag::setTrack(unsigned int i)
{
void ID3v1::Tag::setTrack(unsigned int i) {
d->track = i < 256 ? i : 0;
}
unsigned int ID3v1::Tag::genreNumber() const
{
unsigned int ID3v1::Tag::genreNumber() const {
return d->genre;
}
void ID3v1::Tag::setGenreNumber(unsigned int i)
{
void ID3v1::Tag::setGenreNumber(unsigned int i) {
d->genre = i < 256 ? i : 255;
}
void ID3v1::Tag::setStringHandler(const StringHandler *handler)
{
if(handler)
void ID3v1::Tag::setStringHandler(const StringHandler *handler) {
if (handler)
stringHandler = handler;
else
stringHandler = &defaultStringHandler;
@@ -219,23 +189,21 @@ void ID3v1::Tag::setStringHandler(const StringHandler *handler)
// protected methods
////////////////////////////////////////////////////////////////////////////////
void ID3v1::Tag::read()
{
if(d->file && d->file->isValid()) {
void ID3v1::Tag::read() {
if (d->file && d->file->isValid()) {
d->file->seek(d->tagOffset);
// read the tag -- always 128 bytes
const ByteVector data = d->file->readBlock(128);
// some initial sanity checking
if(data.size() == 128 && data.startsWith("TAG"))
if (data.size() == 128 && data.startsWith("TAG"))
parse(data);
else
debug("ID3v1 tag is not valid or could not be read at the specified offset.");
}
}
void ID3v1::Tag::parse(const ByteVector &data)
{
void ID3v1::Tag::parse(const ByteVector &data) {
int offset = 3;
d->title = stringHandler->parse(data.mid(offset, 30));
@@ -255,11 +223,11 @@ void ID3v1::Tag::parse(const ByteVector &data)
// indicate the end of a C-String, specifically the comment string, a value of
// zero must be assumed to be just that.
if(data[offset + 28] == 0 && data[offset + 29] != 0) {
if (data[offset + 28] == 0 && data[offset + 29] != 0) {
// ID3v1.1 detected
d->comment = stringHandler->parse(data.mid(offset, 28));
d->track = static_cast<unsigned char>(data[offset + 29]);
d->track = static_cast<unsigned char>(data[offset + 29]);
}
else
d->comment = data.mid(offset, 30);

View File

@@ -33,15 +33,15 @@
namespace Strawberry_TagLib {
namespace TagLib {
class File;
class File;
//! An ID3v1 implementation
//! An ID3v1 implementation
namespace ID3v1 {
namespace ID3v1 {
//! A abstraction for the string to data encoding in ID3v1 tags.
//! A abstraction for the string to data encoding in ID3v1 tags.
/*!
/*!
* ID3v1 should in theory always contain ISO-8859-1 (Latin1) data. In
* practice it does not. TagLib by default only supports ISO-8859-1 data
* in ID3v1 tags.
@@ -58,20 +58,19 @@ namespace TagLib {
* \see ID3v1::Tag::setStringHandler()
*/
class TAGLIB_EXPORT StringHandler
{
TAGLIB_IGNORE_MISSING_DESTRUCTOR
public:
// BIC: Add virtual destructor.
StringHandler();
class TAGLIB_EXPORT StringHandler {
TAGLIB_IGNORE_MISSING_DESTRUCTOR
public:
// BIC: Add virtual destructor.
StringHandler();
/*!
/*!
* Decode a string from \a data. The default implementation assumes that
* \a data is an ISO-8859-1 (Latin1) character array.
*/
virtual String parse(const ByteVector &data) const;
virtual String parse(const ByteVector &data) const;
/*!
/*!
* Encode a ByteVector with the data from \a s. The default implementation
* assumes that \a s is an ISO-8859-1 (Latin1) string. If the string is
* does not conform to ISO-8859-1, no value is written.
@@ -80,12 +79,12 @@ namespace TagLib {
* instead do not write an ID3v1 tag in the case that the data is not
* ISO-8859-1.
*/
virtual ByteVector render(const String &s) const;
};
virtual ByteVector render(const String &s) const;
};
//! The main class in the ID3v1 implementation
//! The main class in the ID3v1 implementation
/*!
/*!
* This is an implementation of the ID3v1 format. ID3v1 is both the simplest
* and most common of tag formats but is rather limited. Because of its
* pervasiveness and the way that applications have been written around the
@@ -103,71 +102,70 @@ namespace TagLib {
* truncation happens automatically when the tag is rendered.
*/
class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag
{
public:
/*!
class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
public:
/*!
* Create an ID3v1 tag with default values.
*/
Tag();
Tag();
/*!
/*!
* Create an ID3v1 tag and parse the data in \a file starting at
* \a tagOffset.
*/
Tag(File *file, long tagOffset);
Tag(File *file, long tagOffset);
/*!
/*!
* Destroys this Tag instance.
*/
virtual ~Tag();
virtual ~Tag();
/*!
/*!
* Renders the in memory values to a ByteVector suitable for writing to
* the file.
*/
ByteVector render() const;
ByteVector render() const;
/*!
/*!
* Returns the string "TAG" suitable for usage in locating the tag in a
* file.
*/
static ByteVector fileIdentifier();
static ByteVector fileIdentifier();
// Reimplementations.
// Reimplementations.
virtual String title() const;
virtual String artist() const;
virtual String album() const;
virtual String comment() const;
virtual String genre() const;
virtual unsigned int year() const;
virtual unsigned int track() const;
virtual String title() const;
virtual String artist() const;
virtual String album() const;
virtual String comment() const;
virtual String genre() const;
virtual unsigned int year() const;
virtual unsigned int track() const;
virtual void setTitle(const String &s);
virtual void setArtist(const String &s);
virtual void setAlbum(const String &s);
virtual void setComment(const String &s);
virtual void setGenre(const String &s);
virtual void setYear(unsigned int i);
virtual void setTrack(unsigned int i);
virtual void setTitle(const String &s);
virtual void setArtist(const String &s);
virtual void setAlbum(const String &s);
virtual void setComment(const String &s);
virtual void setGenre(const String &s);
virtual void setYear(unsigned int i);
virtual void setTrack(unsigned int i);
/*!
/*!
* Returns the genre in number.
*
* \note Normally 255 indicates that this tag contains no genre.
*/
unsigned int genreNumber() const;
unsigned int genreNumber() const;
/*!
/*!
* Sets the genre in number to \a i.
*
* \note Valid value is from 0 up to 255. Normally 255 indicates that
* this tag contains no genre.
*/
void setGenreNumber(unsigned int i);
void setGenreNumber(unsigned int i);
/*!
/*!
* Sets the string handler that decides how the ID3v1 data will be
* converted to and from binary data.
* If the parameter \a handler is null, the previous handler is
@@ -178,27 +176,27 @@ namespace TagLib {
*
* \see StringHandler
*/
static void setStringHandler(const StringHandler *handler);
static void setStringHandler(const StringHandler *handler);
protected:
/*!
protected:
/*!
* Reads from the file specified in the constructor.
*/
void read();
/*!
void read();
/*!
* Pareses the body of the tag in \a data.
*/
void parse(const ByteVector &data);
void parse(const ByteVector &data);
private:
Tag(const Tag &);
Tag &operator=(const Tag &);
private:
Tag(const Tag &);
Tag &operator=(const Tag &);
class TagPrivate;
TagPrivate *d;
};
}
}
}
class TagPrivate;
TagPrivate *d;
};
} // namespace ID3v1
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -31,9 +31,8 @@
using namespace Strawberry_TagLib::TagLib;
using namespace ID3v2;
class AttachedPictureFrame::AttachedPictureFramePrivate
{
public:
class AttachedPictureFrame::AttachedPictureFramePrivate {
public:
AttachedPictureFramePrivate() : textEncoding(String::Latin1),
type(AttachedPictureFrame::Other) {}
@@ -48,77 +47,61 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
AttachedPictureFrame::AttachedPictureFrame() :
Frame("APIC"),
d(new AttachedPictureFramePrivate())
{
AttachedPictureFrame::AttachedPictureFrame() : Frame("APIC"),
d(new AttachedPictureFramePrivate()) {
}
AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data) :
Frame(data),
d(new AttachedPictureFramePrivate())
{
AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data) : Frame(data),
d(new AttachedPictureFramePrivate()) {
setData(data);
}
AttachedPictureFrame::~AttachedPictureFrame()
{
AttachedPictureFrame::~AttachedPictureFrame() {
delete d;
}
String AttachedPictureFrame::toString() const
{
String AttachedPictureFrame::toString() const {
String s = "[" + d->mimeType + "]";
return d->description.isEmpty() ? s : d->description + " " + s;
}
String::Type AttachedPictureFrame::textEncoding() const
{
String::Type AttachedPictureFrame::textEncoding() const {
return d->textEncoding;
}
void AttachedPictureFrame::setTextEncoding(String::Type t)
{
void AttachedPictureFrame::setTextEncoding(String::Type t) {
d->textEncoding = t;
}
String AttachedPictureFrame::mimeType() const
{
String AttachedPictureFrame::mimeType() const {
return d->mimeType;
}
void AttachedPictureFrame::setMimeType(const String &m)
{
void AttachedPictureFrame::setMimeType(const String &m) {
d->mimeType = m;
}
AttachedPictureFrame::Type AttachedPictureFrame::type() const
{
AttachedPictureFrame::Type AttachedPictureFrame::type() const {
return d->type;
}
void AttachedPictureFrame::setType(Type t)
{
void AttachedPictureFrame::setType(Type t) {
d->type = t;
}
String AttachedPictureFrame::description() const
{
String AttachedPictureFrame::description() const {
return d->description;
}
void AttachedPictureFrame::setDescription(const String &desc)
{
void AttachedPictureFrame::setDescription(const String &desc) {
d->description = desc;
}
ByteVector AttachedPictureFrame::picture() const
{
ByteVector AttachedPictureFrame::picture() const {
return d->data;
}
void AttachedPictureFrame::setPicture(const ByteVector &p)
{
void AttachedPictureFrame::setPicture(const ByteVector &p) {
d->data = p;
}
@@ -126,9 +109,8 @@ void AttachedPictureFrame::setPicture(const ByteVector &p)
// protected members
////////////////////////////////////////////////////////////////////////////////
void AttachedPictureFrame::parseFields(const ByteVector &data)
{
if(data.size() < 5) {
void AttachedPictureFrame::parseFields(const ByteVector &data) {
if (data.size() < 5) {
debug("A picture frame must contain at least 5 bytes.");
return;
}
@@ -139,7 +121,7 @@ void AttachedPictureFrame::parseFields(const ByteVector &data)
d->mimeType = readStringField(data, String::Latin1, &pos);
/* Now we need at least two more bytes available */
if(static_cast<unsigned int>(pos) + 1 >= data.size()) {
if (static_cast<unsigned int>(pos) + 1 >= data.size()) {
debug("Truncated picture frame.");
return;
}
@@ -150,8 +132,7 @@ void AttachedPictureFrame::parseFields(const ByteVector &data)
d->data = data.mid(pos);
}
ByteVector AttachedPictureFrame::renderFields() const
{
ByteVector AttachedPictureFrame::renderFields() const {
ByteVector data;
String::Type encoding = checkTextEncoding(d->description, d->textEncoding);
@@ -171,10 +152,8 @@ ByteVector AttachedPictureFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new AttachedPictureFramePrivate())
{
AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data, Header *h) : Frame(h),
d(new AttachedPictureFramePrivate()) {
parseFields(fieldData(data));
}
@@ -182,9 +161,8 @@ AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data, Header *h) :
// support for ID3v2.2 PIC frames
////////////////////////////////////////////////////////////////////////////////
void AttachedPictureFrameV22::parseFields(const ByteVector &data)
{
if(data.size() < 5) {
void AttachedPictureFrameV22::parseFields(const ByteVector &data) {
if (data.size() < 5) {
debug("A picture frame must contain at least 5 bytes.");
return;
}
@@ -198,9 +176,11 @@ void AttachedPictureFrameV22::parseFields(const ByteVector &data)
// convert fixed string image type to mime string
if (fixedString.upper() == "JPG") {
d->mimeType = "image/jpeg";
} else if (fixedString.upper() == "PNG") {
}
else if (fixedString.upper() == "PNG") {
d->mimeType = "image/png";
} else {
}
else {
debug("probably unsupported image type");
d->mimeType = "image/" + fixedString;
}
@@ -211,8 +191,7 @@ void AttachedPictureFrameV22::parseFields(const ByteVector &data)
d->data = data.mid(pos);
}
AttachedPictureFrameV22::AttachedPictureFrameV22(const ByteVector &data, Header *h)
{
AttachedPictureFrameV22::AttachedPictureFrameV22(const ByteVector &data, Header *h) {
// set v2.2 header to make fieldData work correctly
setHeader(h, true);

View File

@@ -33,136 +33,134 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
namespace ID3v2 {
//! An ID3v2 attached picture frame implementation
//! An ID3v2 attached picture frame implementation
/*!
/*!
* This is an implementation of ID3v2 attached pictures. Pictures may be
* included in tags, one per APIC frame (but there may be multiple APIC
* frames in a single tag). These pictures are usually in either JPEG or
* PNG format.
*/
class TAGLIB_EXPORT AttachedPictureFrame : public Frame
{
friend class FrameFactory;
class TAGLIB_EXPORT AttachedPictureFrame : public Frame {
friend class FrameFactory;
public:
/*!
public:
/*!
* This describes the function or content of the picture.
*/
enum Type {
//! A type not enumerated below
Other = 0x00,
//! 32x32 PNG image that should be used as the file icon
FileIcon = 0x01,
//! File icon of a different size or format
OtherFileIcon = 0x02,
//! Front cover image of the album
FrontCover = 0x03,
//! Back cover image of the album
BackCover = 0x04,
//! Inside leaflet page of the album
LeafletPage = 0x05,
//! Image from the album itself
Media = 0x06,
//! Picture of the lead artist or soloist
LeadArtist = 0x07,
//! Picture of the artist or performer
Artist = 0x08,
//! Picture of the conductor
Conductor = 0x09,
//! Picture of the band or orchestra
Band = 0x0A,
//! Picture of the composer
Composer = 0x0B,
//! Picture of the lyricist or text writer
Lyricist = 0x0C,
//! Picture of the recording location or studio
RecordingLocation = 0x0D,
//! Picture of the artists during recording
DuringRecording = 0x0E,
//! Picture of the artists during performance
DuringPerformance = 0x0F,
//! Picture from a movie or video related to the track
MovieScreenCapture = 0x10,
//! Picture of a large, coloured fish
ColouredFish = 0x11,
//! Illustration related to the track
Illustration = 0x12,
//! Logo of the band or performer
BandLogo = 0x13,
//! Logo of the publisher (record company)
PublisherLogo = 0x14
};
enum Type {
//! A type not enumerated below
Other = 0x00,
//! 32x32 PNG image that should be used as the file icon
FileIcon = 0x01,
//! File icon of a different size or format
OtherFileIcon = 0x02,
//! Front cover image of the album
FrontCover = 0x03,
//! Back cover image of the album
BackCover = 0x04,
//! Inside leaflet page of the album
LeafletPage = 0x05,
//! Image from the album itself
Media = 0x06,
//! Picture of the lead artist or soloist
LeadArtist = 0x07,
//! Picture of the artist or performer
Artist = 0x08,
//! Picture of the conductor
Conductor = 0x09,
//! Picture of the band or orchestra
Band = 0x0A,
//! Picture of the composer
Composer = 0x0B,
//! Picture of the lyricist or text writer
Lyricist = 0x0C,
//! Picture of the recording location or studio
RecordingLocation = 0x0D,
//! Picture of the artists during recording
DuringRecording = 0x0E,
//! Picture of the artists during performance
DuringPerformance = 0x0F,
//! Picture from a movie or video related to the track
MovieScreenCapture = 0x10,
//! Picture of a large, coloured fish
ColouredFish = 0x11,
//! Illustration related to the track
Illustration = 0x12,
//! Logo of the band or performer
BandLogo = 0x13,
//! Logo of the publisher (record company)
PublisherLogo = 0x14
};
/*!
/*!
* Constructs an empty picture frame. The description, content and text
* encoding should be set manually.
*/
AttachedPictureFrame();
AttachedPictureFrame();
/*!
/*!
* Constructs an AttachedPicture frame based on \a data.
*/
explicit AttachedPictureFrame(const ByteVector &data);
explicit AttachedPictureFrame(const ByteVector &data);
/*!
/*!
* Destroys the AttahcedPictureFrame instance.
*/
virtual ~AttachedPictureFrame();
virtual ~AttachedPictureFrame();
/*!
/*!
* Returns a string containing the description and mime-type
*/
virtual String toString() const;
virtual String toString() const;
/*!
/*!
* Returns the text encoding used for the description.
*
* \see setTextEncoding()
* \see description()
*/
String::Type textEncoding() const;
String::Type textEncoding() const;
/*!
/*!
* Set the text encoding used for the description.
*
* \see description()
*/
void setTextEncoding(String::Type t);
void setTextEncoding(String::Type t);
/*!
/*!
* Returns the mime type of the image. This should in most cases be
* "image/png" or "image/jpeg".
*/
String mimeType() const;
String mimeType() const;
/*!
/*!
* Sets the mime type of the image. This should in most cases be
* "image/png" or "image/jpeg".
*/
void setMimeType(const String &m);
void setMimeType(const String &m);
/*!
/*!
* Returns the type of the image.
*
* \see Type
* \see setType()
*/
Type type() const;
Type type() const;
/*!
/*!
* Sets the type for the image.
*
* \see Type
* \see type()
*/
void setType(Type t);
void setType(Type t);
/*!
/*!
* Returns a text description of the image.
*
* \see setDescription()
@@ -170,9 +168,9 @@ namespace TagLib {
* \see setTextEncoding()
*/
String description() const;
String description() const;
/*!
/*!
* Sets a textual description of the image to \a desc.
*
* \see description()
@@ -180,9 +178,9 @@ namespace TagLib {
* \see setTextEncoding()
*/
void setDescription(const String &desc);
void setDescription(const String &desc);
/*!
/*!
* Returns the image data as a ByteVector.
*
* \note ByteVector has a data() method that returns a const char * which
@@ -191,9 +189,9 @@ namespace TagLib {
* \see setPicture()
* \see mimeType()
*/
ByteVector picture() const;
ByteVector picture() const;
/*!
/*!
* Sets the image data to \a p. \a p should be of the type specified in
* this frame's mime-type specification.
*
@@ -201,32 +199,31 @@ namespace TagLib {
* \see mimeType()
* \see setMimeType()
*/
void setPicture(const ByteVector &p);
void setPicture(const ByteVector &p);
protected:
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
class AttachedPictureFramePrivate;
AttachedPictureFramePrivate *d;
protected:
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
class AttachedPictureFramePrivate;
AttachedPictureFramePrivate *d;
private:
AttachedPictureFrame(const AttachedPictureFrame &);
AttachedPictureFrame &operator=(const AttachedPictureFrame &);
AttachedPictureFrame(const ByteVector &data, Header *h);
private:
AttachedPictureFrame(const AttachedPictureFrame &);
AttachedPictureFrame &operator=(const AttachedPictureFrame &);
AttachedPictureFrame(const ByteVector &data, Header *h);
};
};
//! support for ID3v2.2 PIC frames
class TAGLIB_EXPORT AttachedPictureFrameV22 : public AttachedPictureFrame {
protected:
virtual void parseFields(const ByteVector &data);
//! support for ID3v2.2 PIC frames
class TAGLIB_EXPORT AttachedPictureFrameV22 : public AttachedPictureFrame
{
protected:
virtual void parseFields(const ByteVector &data);
private:
AttachedPictureFrameV22(const ByteVector &data, Header *h);
friend class FrameFactory;
};
}
}
}
private:
AttachedPictureFrameV22(const ByteVector &data, Header *h);
friend class FrameFactory;
};
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -33,16 +33,13 @@
using namespace Strawberry_TagLib::TagLib;
using namespace ID3v2;
class ChapterFrame::ChapterFramePrivate
{
public:
ChapterFramePrivate() :
tagHeader(0),
startTime(0),
endTime(0),
startOffset(0),
endOffset(0)
{
class ChapterFrame::ChapterFramePrivate {
public:
ChapterFramePrivate() : tagHeader(0),
startTime(0),
endTime(0),
startOffset(0),
endOffset(0) {
embeddedFrameList.setAutoDelete(true);
}
@@ -60,21 +57,17 @@ public:
// public methods
////////////////////////////////////////////////////////////////////////////////
ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data) :
ID3v2::Frame(data),
d(new ChapterFramePrivate())
{
ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data) : ID3v2::Frame(data),
d(new ChapterFramePrivate()) {
d->tagHeader = tagHeader;
setData(data);
}
ChapterFrame::ChapterFrame(const ByteVector &elementID,
unsigned int startTime, unsigned int endTime,
unsigned int startOffset, unsigned int endOffset,
const FrameList &embeddedFrames) :
ID3v2::Frame("CHAP"),
d(new ChapterFramePrivate())
{
unsigned int startTime, unsigned int endTime,
unsigned int startOffset, unsigned int endOffset,
const FrameList &embeddedFrames) : ID3v2::Frame("CHAP"),
d(new ChapterFramePrivate()) {
// setElementID has a workaround for a previously silly API where you had to
// specifically include the null byte.
@@ -85,92 +78,77 @@ ChapterFrame::ChapterFrame(const ByteVector &elementID,
d->startOffset = startOffset;
d->endOffset = endOffset;
for(FrameList::ConstIterator it = embeddedFrames.begin();
it != embeddedFrames.end(); ++it)
for (FrameList::ConstIterator it = embeddedFrames.begin();
it != embeddedFrames.end();
++it)
addEmbeddedFrame(*it);
}
ChapterFrame::~ChapterFrame()
{
ChapterFrame::~ChapterFrame() {
delete d;
}
ByteVector ChapterFrame::elementID() const
{
ByteVector ChapterFrame::elementID() const {
return d->elementID;
}
unsigned int ChapterFrame::startTime() const
{
unsigned int ChapterFrame::startTime() const {
return d->startTime;
}
unsigned int ChapterFrame::endTime() const
{
unsigned int ChapterFrame::endTime() const {
return d->endTime;
}
unsigned int ChapterFrame::startOffset() const
{
unsigned int ChapterFrame::startOffset() const {
return d->startOffset;
}
unsigned int ChapterFrame::endOffset() const
{
unsigned int ChapterFrame::endOffset() const {
return d->endOffset;
}
void ChapterFrame::setElementID(const ByteVector &eID)
{
void ChapterFrame::setElementID(const ByteVector &eID) {
d->elementID = eID;
if(d->elementID.endsWith(char(0)))
if (d->elementID.endsWith(char(0)))
d->elementID = d->elementID.mid(0, d->elementID.size() - 1);
}
void ChapterFrame::setStartTime(const unsigned int &sT)
{
void ChapterFrame::setStartTime(const unsigned int &sT) {
d->startTime = sT;
}
void ChapterFrame::setEndTime(const unsigned int &eT)
{
void ChapterFrame::setEndTime(const unsigned int &eT) {
d->endTime = eT;
}
void ChapterFrame::setStartOffset(const unsigned int &sO)
{
void ChapterFrame::setStartOffset(const unsigned int &sO) {
d->startOffset = sO;
}
void ChapterFrame::setEndOffset(const unsigned int &eO)
{
void ChapterFrame::setEndOffset(const unsigned int &eO) {
d->endOffset = eO;
}
const FrameListMap &ChapterFrame::embeddedFrameListMap() const
{
const FrameListMap &ChapterFrame::embeddedFrameListMap() const {
return d->embeddedFrameListMap;
}
const FrameList &ChapterFrame::embeddedFrameList() const
{
const FrameList &ChapterFrame::embeddedFrameList() const {
return d->embeddedFrameList;
}
const FrameList &ChapterFrame::embeddedFrameList(const ByteVector &frameID) const
{
const FrameList &ChapterFrame::embeddedFrameList(const ByteVector &frameID) const {
return d->embeddedFrameListMap[frameID];
}
void ChapterFrame::addEmbeddedFrame(Frame *frame)
{
void ChapterFrame::addEmbeddedFrame(Frame *frame) {
d->embeddedFrameList.append(frame);
d->embeddedFrameListMap[frame->frameID()].append(frame);
}
void ChapterFrame::removeEmbeddedFrame(Frame *frame, bool del)
{
void ChapterFrame::removeEmbeddedFrame(Frame *frame, bool del) {
// remove the frame from the frame list
FrameList::Iterator it = d->embeddedFrameList.find(frame);
d->embeddedFrameList.erase(it);
@@ -180,33 +158,32 @@ void ChapterFrame::removeEmbeddedFrame(Frame *frame, bool del)
d->embeddedFrameListMap[frame->frameID()].erase(it);
// ...and delete as desired
if(del)
if (del)
delete frame;
}
void ChapterFrame::removeEmbeddedFrames(const ByteVector &id)
{
void ChapterFrame::removeEmbeddedFrames(const ByteVector &id) {
FrameList l = d->embeddedFrameListMap[id];
for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
for (FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
removeEmbeddedFrame(*it, true);
}
String ChapterFrame::toString() const
{
String ChapterFrame::toString() const {
String s = String(d->elementID) +
": start time: " + String::number(d->startTime) +
", end time: " + String::number(d->endTime);
": start time: " + String::number(d->startTime) +
", end time: " + String::number(d->endTime);
if(d->startOffset != 0xFFFFFFFF)
if (d->startOffset != 0xFFFFFFFF)
s += ", start offset: " + String::number(d->startOffset);
if(d->endOffset != 0xFFFFFFFF)
if (d->endOffset != 0xFFFFFFFF)
s += ", end offset: " + String::number(d->endOffset);
if(!d->embeddedFrameList.isEmpty()) {
if (!d->embeddedFrameList.isEmpty()) {
StringList frameIDs;
for(FrameList::ConstIterator it = d->embeddedFrameList.begin();
it != d->embeddedFrameList.end(); ++it)
for (FrameList::ConstIterator it = d->embeddedFrameList.begin();
it != d->embeddedFrameList.end();
++it)
frameIDs.append((*it)->frameID());
s += ", sub-frames: [ " + frameIDs.toString(", ") + " ]";
}
@@ -214,8 +191,7 @@ String ChapterFrame::toString() const
return s;
}
PropertyMap ChapterFrame::asProperties() const
{
PropertyMap ChapterFrame::asProperties() const {
PropertyMap map;
map.unsupportedData().append(frameID() + String("/") + d->elementID);
@@ -223,26 +199,24 @@ PropertyMap ChapterFrame::asProperties() const
return map;
}
ChapterFrame *ChapterFrame::findByElementID(const ID3v2::Tag *tag, const ByteVector &eID) // static
ChapterFrame *ChapterFrame::findByElementID(const ID3v2::Tag *tag, const ByteVector &eID) // static
{
ID3v2::FrameList comments = tag->frameList("CHAP");
for(ID3v2::FrameList::ConstIterator it = comments.begin();
it != comments.end();
++it)
{
for (ID3v2::FrameList::ConstIterator it = comments.begin();
it != comments.end();
++it) {
ChapterFrame *frame = dynamic_cast<ChapterFrame *>(*it);
if(frame && frame->elementID() == eID)
if (frame && frame->elementID() == eID)
return frame;
}
return nullptr;
}
void ChapterFrame::parseFields(const ByteVector &data)
{
void ChapterFrame::parseFields(const ByteVector &data) {
unsigned int size = data.size();
if(size < 18) {
if (size < 18) {
debug("A CHAP frame must contain at least 18 bytes (1 byte element ID "
"terminated by null and 4x4 bytes for start and end time and offset).");
return;
@@ -263,17 +237,17 @@ void ChapterFrame::parseFields(const ByteVector &data)
// Embedded frames are optional
if(size < header()->size())
if (size < header()->size())
return;
while(embPos < size - header()->size()) {
while (embPos < size - header()->size()) {
Frame *frame = FrameFactory::instance()->createFrame(data.mid(pos + embPos), d->tagHeader);
if(!frame)
if (!frame)
return;
// Checks to make sure that frame parsed correctly.
if(frame->size() <= 0) {
if (frame->size() <= 0) {
delete frame;
return;
}
@@ -283,8 +257,7 @@ void ChapterFrame::parseFields(const ByteVector &data)
}
}
ByteVector ChapterFrame::renderFields() const
{
ByteVector ChapterFrame::renderFields() const {
ByteVector data;
data.append(d->elementID);
@@ -294,16 +267,14 @@ ByteVector ChapterFrame::renderFields() const
data.append(ByteVector::fromUInt(d->startOffset, true));
data.append(ByteVector::fromUInt(d->endOffset, true));
FrameList l = d->embeddedFrameList;
for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
for (FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
data.append((*it)->render());
return data;
}
ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data, Header *h) :
Frame(h),
d(new ChapterFramePrivate())
{
ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data, Header *h) : Frame(h),
d(new ChapterFramePrivate()) {
d->tagHeader = tagHeader;
parseFields(fieldData(data));
}

View File

@@ -33,27 +33,26 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
namespace ID3v2 {
/*!
/*!
* This is an implementation of ID3v2 chapter frames. The purpose of this
* frame is to describe a single chapter within an audio file.
*/
//! An implementation of ID3v2 chapter frames
//! An implementation of ID3v2 chapter frames
class TAGLIB_EXPORT ChapterFrame : public ID3v2::Frame
{
friend class FrameFactory;
class TAGLIB_EXPORT ChapterFrame : public ID3v2::Frame {
friend class FrameFactory;
public:
/*!
public:
/*!
* Creates a chapter frame based on \a data. \a tagHeader is required as
* the internal frames are parsed based on the tag version.
*/
ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data);
ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data);
/*!
/*!
* Creates a chapter frame with the element ID \a elementID, start time
* \a startTime, end time \a endTime, start offset \a startOffset,
* end offset \a endOffset and optionally a list of embedded frames,
@@ -62,95 +61,95 @@ namespace TagLib {
*
* All times are in milliseconds.
*/
ChapterFrame(const ByteVector &elementID,
unsigned int startTime, unsigned int endTime,
unsigned int startOffset, unsigned int endOffset,
const FrameList &embeddedFrames = FrameList());
ChapterFrame(const ByteVector &elementID,
unsigned int startTime, unsigned int endTime,
unsigned int startOffset, unsigned int endOffset,
const FrameList &embeddedFrames = FrameList());
/*!
/*!
* Destroys the frame.
*/
virtual ~ChapterFrame();
virtual ~ChapterFrame();
/*!
/*!
* Returns the element ID of the frame. Element ID
* is a null terminated string, however it's not human-readable.
*
* \see setElementID()
*/
ByteVector elementID() const;
ByteVector elementID() const;
/*!
/*!
* Returns time of chapter's start (in milliseconds).
*
* \see setStartTime()
*/
unsigned int startTime() const;
unsigned int startTime() const;
/*!
/*!
* Returns time of chapter's end (in milliseconds).
*
* \see setEndTime()
*/
unsigned int endTime() const;
unsigned int endTime() const;
/*!
/*!
* Returns zero based byte offset (count of bytes from the beginning
* of the audio file) of chapter's start.
*
* \note If returned value is 0xFFFFFFFF, start time should be used instead.
* \see setStartOffset()
*/
unsigned int startOffset() const;
unsigned int startOffset() const;
/*!
/*!
* Returns zero based byte offset (count of bytes from the beginning
* of the audio file) of chapter's end.
*
* \note If returned value is 0xFFFFFFFF, end time should be used instead.
* \see setEndOffset()
*/
unsigned int endOffset() const;
unsigned int endOffset() const;
/*!
/*!
* Sets the element ID of the frame to \a eID. If \a eID isn't
* null terminated, a null char is appended automatically.
*
* \see elementID()
*/
void setElementID(const ByteVector &eID);
void setElementID(const ByteVector &eID);
/*!
/*!
* Sets time of chapter's start (in milliseconds) to \a sT.
*
* \see startTime()
*/
void setStartTime(const unsigned int &sT);
void setStartTime(const unsigned int &sT);
/*!
/*!
* Sets time of chapter's end (in milliseconds) to \a eT.
*
* \see endTime()
*/
void setEndTime(const unsigned int &eT);
void setEndTime(const unsigned int &eT);
/*!
/*!
* Sets zero based byte offset (count of bytes from the beginning
* of the audio file) of chapter's start to \a sO.
*
* \see startOffset()
*/
void setStartOffset(const unsigned int &sO);
void setStartOffset(const unsigned int &sO);
/*!
/*!
* Sets zero based byte offset (count of bytes from the beginning
* of the audio file) of chapter's end to \a eO.
*
* \see endOffset()
*/
void setEndOffset(const unsigned int &eO);
void setEndOffset(const unsigned int &eO);
/*!
/*!
* Returns a reference to the frame list map. This is an FrameListMap of
* all of the frames embedded in the CHAP frame.
*
@@ -164,9 +163,9 @@ namespace TagLib {
*
* \see embeddedFrameList()
*/
const FrameListMap &embeddedFrameListMap() const;
const FrameListMap &embeddedFrameListMap() const;
/*!
/*!
* Returns a reference to the embedded frame list. This is an FrameList
* of all of the frames embedded in the CHAP frame in the order that they
* were parsed.
@@ -177,9 +176,9 @@ namespace TagLib {
* \warning You should not modify this data structure directly, instead
* use addEmbeddedFrame() and removeEmbeddedFrame().
*/
const FrameList &embeddedFrameList() const;
const FrameList &embeddedFrameList() const;
/*!
/*!
* Returns the embedded frame list for frames with the id \a frameID
* or an empty list if there are no embedded frames of that type. This
* is just a convenience and is equivalent to:
@@ -190,62 +189,62 @@ namespace TagLib {
*
* \see embeddedFrameListMap()
*/
const FrameList &embeddedFrameList(const ByteVector &frameID) const;
const FrameList &embeddedFrameList(const ByteVector &frameID) const;
/*!
/*!
* Add an embedded frame to the CHAP frame. At this point the CHAP frame
* takes ownership of the embedded frame and will handle freeing its memory.
*
* \note Using this method will invalidate any pointers on the list
* returned by embeddedFrameList()
*/
void addEmbeddedFrame(Frame *frame);
void addEmbeddedFrame(Frame *frame);
/*!
/*!
* Remove an embedded frame from the CHAP frame. If \a del is true the frame's
* memory will be freed; if it is false, it must be deleted by the user.
*
* \note Using this method will invalidate any pointers on the list
* returned by embeddedFrameList()
*/
void removeEmbeddedFrame(Frame *frame, bool del = true);
void removeEmbeddedFrame(Frame *frame, bool del = true);
/*!
/*!
* Remove all embedded frames of type \a id from the CHAP frame and free their
* memory.
*
* \note Using this method will invalidate any pointers on the list
* returned by embeddedFrameList()
*/
void removeEmbeddedFrames(const ByteVector &id);
void removeEmbeddedFrames(const ByteVector &id);
virtual String toString() const;
virtual String toString() const;
PropertyMap asProperties() const;
PropertyMap asProperties() const;
/*!
/*!
* CHAP frames each have a unique element ID. This searches for a CHAP
* frame with the element ID \a eID and returns a pointer to it. This
* can be used to link CTOC and CHAP frames together.
*
* \see elementID()
*/
static ChapterFrame *findByElementID(const Tag *tag, const ByteVector &eID);
static ChapterFrame *findByElementID(const Tag *tag, const ByteVector &eID);
protected:
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
protected:
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
private:
ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data, Header *h);
ChapterFrame(const ChapterFrame &);
ChapterFrame &operator=(const ChapterFrame &);
private:
ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data, Header *h);
ChapterFrame(const ChapterFrame &);
ChapterFrame &operator=(const ChapterFrame &);
class ChapterFramePrivate;
ChapterFramePrivate *d;
};
}
}
}
class ChapterFramePrivate;
ChapterFramePrivate *d;
};
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -34,9 +34,8 @@
using namespace Strawberry_TagLib::TagLib;
using namespace ID3v2;
class CommentsFrame::CommentsFramePrivate
{
public:
class CommentsFrame::CommentsFramePrivate {
public:
CommentsFramePrivate() : textEncoding(String::Latin1) {}
String::Type textEncoding;
ByteVector language;
@@ -48,91 +47,75 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
CommentsFrame::CommentsFrame(String::Type encoding) :
Frame("COMM"),
d(new CommentsFramePrivate())
{
CommentsFrame::CommentsFrame(String::Type encoding) : Frame("COMM"),
d(new CommentsFramePrivate()) {
d->textEncoding = encoding;
}
CommentsFrame::CommentsFrame(const ByteVector &data) :
Frame(data),
d(new CommentsFramePrivate())
{
CommentsFrame::CommentsFrame(const ByteVector &data) : Frame(data),
d(new CommentsFramePrivate()) {
setData(data);
}
CommentsFrame::~CommentsFrame()
{
CommentsFrame::~CommentsFrame() {
delete d;
}
String CommentsFrame::toString() const
{
String CommentsFrame::toString() const {
return d->text;
}
ByteVector CommentsFrame::language() const
{
ByteVector CommentsFrame::language() const {
return d->language;
}
String CommentsFrame::description() const
{
String CommentsFrame::description() const {
return d->description;
}
String CommentsFrame::text() const
{
String CommentsFrame::text() const {
return d->text;
}
void CommentsFrame::setLanguage(const ByteVector &languageEncoding)
{
void CommentsFrame::setLanguage(const ByteVector &languageEncoding) {
d->language = languageEncoding.mid(0, 3);
}
void CommentsFrame::setDescription(const String &s)
{
void CommentsFrame::setDescription(const String &s) {
d->description = s;
}
void CommentsFrame::setText(const String &s)
{
void CommentsFrame::setText(const String &s) {
d->text = s;
}
String::Type CommentsFrame::textEncoding() const
{
String::Type CommentsFrame::textEncoding() const {
return d->textEncoding;
}
void CommentsFrame::setTextEncoding(String::Type encoding)
{
void CommentsFrame::setTextEncoding(String::Type encoding) {
d->textEncoding = encoding;
}
PropertyMap CommentsFrame::asProperties() const
{
PropertyMap CommentsFrame::asProperties() const {
String key = description().upper();
PropertyMap map;
if(key.isEmpty() || key == "COMMENT")
if (key.isEmpty() || key == "COMMENT")
map.insert("COMMENT", text());
else
map.insert("COMMENT:" + key, text());
return map;
}
CommentsFrame *CommentsFrame::findByDescription(const ID3v2::Tag *tag, const String &d) // static
CommentsFrame *CommentsFrame::findByDescription(const ID3v2::Tag *tag, const String &d) // static
{
ID3v2::FrameList comments = tag->frameList("COMM");
for(ID3v2::FrameList::ConstIterator it = comments.begin();
it != comments.end();
++it)
{
for (ID3v2::FrameList::ConstIterator it = comments.begin();
it != comments.end();
++it) {
CommentsFrame *frame = dynamic_cast<CommentsFrame *>(*it);
if(frame && frame->description() == d)
if (frame && frame->description() == d)
return frame;
}
@@ -143,9 +126,8 @@ CommentsFrame *CommentsFrame::findByDescription(const ID3v2::Tag *tag, const Str
// protected members
////////////////////////////////////////////////////////////////////////////////
void CommentsFrame::parseFields(const ByteVector &data)
{
if(data.size() < 5) {
void CommentsFrame::parseFields(const ByteVector &data) {
if (data.size() < 5) {
debug("A comment frame must contain at least 5 bytes.");
return;
}
@@ -157,19 +139,19 @@ void CommentsFrame::parseFields(const ByteVector &data)
ByteVectorList l = ByteVectorList::split(data.mid(4), textDelimiter(d->textEncoding), byteAlign, 2);
if(l.size() == 2) {
if(d->textEncoding == String::Latin1) {
if (l.size() == 2) {
if (d->textEncoding == String::Latin1) {
d->description = Tag::latin1StringHandler()->parse(l.front());
d->text = Tag::latin1StringHandler()->parse(l.back());
} else {
}
else {
d->description = String(l.front(), d->textEncoding);
d->text = String(l.back(), d->textEncoding);
}
}
}
ByteVector CommentsFrame::renderFields() const
{
ByteVector CommentsFrame::renderFields() const {
ByteVector v;
String::Type encoding = d->textEncoding;
@@ -190,9 +172,7 @@ ByteVector CommentsFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
CommentsFrame::CommentsFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new CommentsFramePrivate())
{
CommentsFrame::CommentsFrame(const ByteVector &data, Header *h) : Frame(h),
d(new CommentsFramePrivate()) {
parseFields(fieldData(data));
}

View File

@@ -32,44 +32,43 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
namespace ID3v2 {
//! An implementation of ID3v2 comments
//! An implementation of ID3v2 comments
/*!
/*!
* This implements the ID3v2 comment format. An ID3v2 comment consists of
* a language encoding, a description and a single text field.
*/
class TAGLIB_EXPORT CommentsFrame : public Frame
{
friend class FrameFactory;
class TAGLIB_EXPORT CommentsFrame : public Frame {
friend class FrameFactory;
public:
/*!
public:
/*!
* Construct an empty comment frame that will use the text encoding
* \a encoding.
*/
explicit CommentsFrame(String::Type encoding = String::Latin1);
explicit CommentsFrame(String::Type encoding = String::Latin1);
/*!
/*!
* Construct a comment based on the data in \a data.
*/
explicit CommentsFrame(const ByteVector &data);
explicit CommentsFrame(const ByteVector &data);
/*!
/*!
* Destroys this CommentFrame instance.
*/
virtual ~CommentsFrame();
virtual ~CommentsFrame();
/*!
/*!
* Returns the text of this comment.
*
* \see text()
*/
virtual String toString() const;
virtual String toString() const;
/*!
/*!
* Returns the language encoding as a 3 byte encoding as specified by
* <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a>.
*
@@ -77,48 +76,48 @@ namespace TagLib {
*
* \see setLanguage()
*/
ByteVector language() const;
ByteVector language() const;
/*!
/*!
* Returns the description of this comment.
*
* \note Most taggers simply ignore this value.
*
* \see setDescription()
*/
String description() const;
String description() const;
/*!
/*!
* Returns the text of this comment.
*
* \see setText()
*/
String text() const;
String text() const;
/*!
/*!
* Set the language using the 3 byte language code from
* <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a> to
* \a languageCode.
*
* \see language()
*/
void setLanguage(const ByteVector &languageCode);
void setLanguage(const ByteVector &languageCode);
/*!
/*!
* Sets the description of the comment to \a s.
*
* \see description()
*/
void setDescription(const String &s);
void setDescription(const String &s);
/*!
/*!
* Sets the text portion of the comment to \a s.
*
* \see text()
*/
virtual void setText(const String &s);
virtual void setText(const String &s);
/*!
/*!
* Returns the text encoding that will be used in rendering this frame.
* This defaults to the type that was either specified in the constructor
* or read from the frame when parsed.
@@ -126,18 +125,18 @@ namespace TagLib {
* \see setTextEncoding()
* \see render()
*/
String::Type textEncoding() const;
String::Type textEncoding() const;
/*!
/*!
* Sets the text encoding to be used when rendering this frame to
* \a encoding.
*
* \see textEncoding()
* \see render()
*/
void setTextEncoding(String::Type encoding);
void setTextEncoding(String::Type encoding);
/*!
/*!
* Parses this frame as PropertyMap with a single key.
* - if description() is empty or "COMMENT", the key will be "COMMENT"
* - if description() is not a valid PropertyMap key, the frame will be
@@ -146,36 +145,36 @@ namespace TagLib {
* - otherwise, the key will be "COMMENT:<description>"
* - The single value will be the frame's text().
*/
PropertyMap asProperties() const;
PropertyMap asProperties() const;
/*!
/*!
* Comments each have a unique description. This searches for a comment
* frame with the description \a d and returns a pointer to it. If no
* frame is found that matches the given description null is returned.
*
* \see description()
*/
static CommentsFrame *findByDescription(const Tag *tag, const String &d);
static CommentsFrame *findByDescription(const Tag *tag, const String &d);
protected:
// Reimplementations.
protected:
// Reimplementations.
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
private:
/*!
private:
/*!
* The constructor used by the FrameFactory.
*/
CommentsFrame(const ByteVector &data, Header *h);
CommentsFrame(const CommentsFrame &);
CommentsFrame &operator=(const CommentsFrame &);
CommentsFrame(const ByteVector &data, Header *h);
CommentsFrame(const CommentsFrame &);
CommentsFrame &operator=(const CommentsFrame &);
class CommentsFramePrivate;
CommentsFramePrivate *d;
};
class CommentsFramePrivate;
CommentsFramePrivate *d;
};
}
}
}
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -32,11 +32,9 @@
using namespace Strawberry_TagLib::TagLib;
using namespace ID3v2;
class EventTimingCodesFrame::EventTimingCodesFramePrivate
{
public:
EventTimingCodesFramePrivate() :
timestampFormat(EventTimingCodesFrame::AbsoluteMilliseconds) {}
class EventTimingCodesFrame::EventTimingCodesFramePrivate {
public:
EventTimingCodesFramePrivate() : timestampFormat(EventTimingCodesFrame::AbsoluteMilliseconds) {}
EventTimingCodesFrame::TimestampFormat timestampFormat;
EventTimingCodesFrame::SynchedEventList synchedEvents;
};
@@ -45,50 +43,40 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
EventTimingCodesFrame::EventTimingCodesFrame() :
Frame("ETCO"),
d(new EventTimingCodesFramePrivate())
{
EventTimingCodesFrame::EventTimingCodesFrame() : Frame("ETCO"),
d(new EventTimingCodesFramePrivate()) {
}
EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data) :
Frame(data),
d(new EventTimingCodesFramePrivate())
{
EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data) : Frame(data),
d(new EventTimingCodesFramePrivate()) {
setData(data);
}
EventTimingCodesFrame::~EventTimingCodesFrame()
{
EventTimingCodesFrame::~EventTimingCodesFrame() {
delete d;
}
String EventTimingCodesFrame::toString() const
{
String EventTimingCodesFrame::toString() const {
return String();
}
EventTimingCodesFrame::TimestampFormat
EventTimingCodesFrame::timestampFormat() const
{
EventTimingCodesFrame::timestampFormat() const {
return d->timestampFormat;
}
EventTimingCodesFrame::SynchedEventList
EventTimingCodesFrame::synchedEvents() const
{
EventTimingCodesFrame::synchedEvents() const {
return d->synchedEvents;
}
void EventTimingCodesFrame::setTimestampFormat(
EventTimingCodesFrame::TimestampFormat f)
{
EventTimingCodesFrame::TimestampFormat f) {
d->timestampFormat = f;
}
void EventTimingCodesFrame::setSynchedEvents(
const EventTimingCodesFrame::SynchedEventList &e)
{
const EventTimingCodesFrame::SynchedEventList &e) {
d->synchedEvents = e;
}
@@ -96,10 +84,9 @@ void EventTimingCodesFrame::setSynchedEvents(
// protected members
////////////////////////////////////////////////////////////////////////////////
void EventTimingCodesFrame::parseFields(const ByteVector &data)
{
void EventTimingCodesFrame::parseFields(const ByteVector &data) {
const int end = data.size();
if(end < 1) {
if (end < 1) {
debug("An event timing codes frame must contain at least 1 byte.");
return;
}
@@ -108,7 +95,7 @@ void EventTimingCodesFrame::parseFields(const ByteVector &data)
int pos = 1;
d->synchedEvents.clear();
while(pos + 4 < end) {
while (pos + 4 < end) {
EventType type = static_cast<EventType>(static_cast<unsigned char>(data[pos++]));
unsigned int time = data.toUInt(pos, true);
pos += 4;
@@ -116,14 +103,13 @@ void EventTimingCodesFrame::parseFields(const ByteVector &data)
}
}
ByteVector EventTimingCodesFrame::renderFields() const
{
ByteVector EventTimingCodesFrame::renderFields() const {
ByteVector v;
v.append(char(d->timestampFormat));
for(SynchedEventList::ConstIterator it = d->synchedEvents.begin();
it != d->synchedEvents.end();
++it) {
for (SynchedEventList::ConstIterator it = d->synchedEvents.begin();
it != d->synchedEvents.end();
++it) {
const SynchedEvent &entry = *it;
v.append(char(entry.type));
v.append(ByteVector::fromUInt(entry.time));
@@ -136,9 +122,7 @@ ByteVector EventTimingCodesFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new EventTimingCodesFramePrivate())
{
EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data, Header *h) : Frame(h),
d(new EventTimingCodesFramePrivate()) {
parseFields(fieldData(data));
}

View File

@@ -32,156 +32,154 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
namespace ID3v2 {
//! ID3v2 event timing codes frame
/*!
//! ID3v2 event timing codes frame
/*!
* An implementation of ID3v2 event timing codes.
*/
class TAGLIB_EXPORT EventTimingCodesFrame : public Frame
{
friend class FrameFactory;
class TAGLIB_EXPORT EventTimingCodesFrame : public Frame {
friend class FrameFactory;
public:
/*!
public:
/*!
* Specifies the timestamp format used.
*/
enum TimestampFormat {
//! The timestamp is of unknown format.
Unknown = 0x00,
//! The timestamp represents the number of MPEG frames since
//! the beginning of the audio stream.
AbsoluteMpegFrames = 0x01,
//! The timestamp represents the number of milliseconds since
//! the beginning of the audio stream.
AbsoluteMilliseconds = 0x02
};
enum TimestampFormat {
//! The timestamp is of unknown format.
Unknown = 0x00,
//! The timestamp represents the number of MPEG frames since
//! the beginning of the audio stream.
AbsoluteMpegFrames = 0x01,
//! The timestamp represents the number of milliseconds since
//! the beginning of the audio stream.
AbsoluteMilliseconds = 0x02
};
/*!
/*!
* Event types defined in id3v2.4.0-frames.txt 4.5. Event timing codes.
*/
enum EventType {
Padding = 0x00,
EndOfInitialSilence = 0x01,
IntroStart = 0x02,
MainPartStart = 0x03,
OutroStart = 0x04,
OutroEnd = 0x05,
VerseStart = 0x06,
RefrainStart = 0x07,
InterludeStart = 0x08,
ThemeStart = 0x09,
VariationStart = 0x0a,
KeyChange = 0x0b,
TimeChange = 0x0c,
MomentaryUnwantedNoise = 0x0d,
SustainedNoise = 0x0e,
SustainedNoiseEnd = 0x0f,
IntroEnd = 0x10,
MainPartEnd = 0x11,
VerseEnd = 0x12,
RefrainEnd = 0x13,
ThemeEnd = 0x14,
Profanity = 0x15,
ProfanityEnd = 0x16,
NotPredefinedSynch0 = 0xe0,
NotPredefinedSynch1 = 0xe1,
NotPredefinedSynch2 = 0xe2,
NotPredefinedSynch3 = 0xe3,
NotPredefinedSynch4 = 0xe4,
NotPredefinedSynch5 = 0xe5,
NotPredefinedSynch6 = 0xe6,
NotPredefinedSynch7 = 0xe7,
NotPredefinedSynch8 = 0xe8,
NotPredefinedSynch9 = 0xe9,
NotPredefinedSynchA = 0xea,
NotPredefinedSynchB = 0xeb,
NotPredefinedSynchC = 0xec,
NotPredefinedSynchD = 0xed,
NotPredefinedSynchE = 0xee,
NotPredefinedSynchF = 0xef,
AudioEnd = 0xfd,
AudioFileEnds = 0xfe
};
enum EventType {
Padding = 0x00,
EndOfInitialSilence = 0x01,
IntroStart = 0x02,
MainPartStart = 0x03,
OutroStart = 0x04,
OutroEnd = 0x05,
VerseStart = 0x06,
RefrainStart = 0x07,
InterludeStart = 0x08,
ThemeStart = 0x09,
VariationStart = 0x0a,
KeyChange = 0x0b,
TimeChange = 0x0c,
MomentaryUnwantedNoise = 0x0d,
SustainedNoise = 0x0e,
SustainedNoiseEnd = 0x0f,
IntroEnd = 0x10,
MainPartEnd = 0x11,
VerseEnd = 0x12,
RefrainEnd = 0x13,
ThemeEnd = 0x14,
Profanity = 0x15,
ProfanityEnd = 0x16,
NotPredefinedSynch0 = 0xe0,
NotPredefinedSynch1 = 0xe1,
NotPredefinedSynch2 = 0xe2,
NotPredefinedSynch3 = 0xe3,
NotPredefinedSynch4 = 0xe4,
NotPredefinedSynch5 = 0xe5,
NotPredefinedSynch6 = 0xe6,
NotPredefinedSynch7 = 0xe7,
NotPredefinedSynch8 = 0xe8,
NotPredefinedSynch9 = 0xe9,
NotPredefinedSynchA = 0xea,
NotPredefinedSynchB = 0xeb,
NotPredefinedSynchC = 0xec,
NotPredefinedSynchD = 0xed,
NotPredefinedSynchE = 0xee,
NotPredefinedSynchF = 0xef,
AudioEnd = 0xfd,
AudioFileEnds = 0xfe
};
/*!
/*!
* Single entry of time stamp and event.
*/
struct SynchedEvent {
SynchedEvent(unsigned int ms, EventType t) : time(ms), type(t) {}
unsigned int time;
EventType type;
};
struct SynchedEvent {
SynchedEvent(unsigned int ms, EventType t) : time(ms), type(t) {}
unsigned int time;
EventType type;
};
/*!
/*!
* List of synchronized events.
*/
typedef Strawberry_TagLib::TagLib::List<SynchedEvent> SynchedEventList;
typedef Strawberry_TagLib::TagLib::List<SynchedEvent> SynchedEventList;
/*!
/*!
* Construct an empty event timing codes frame.
*/
explicit EventTimingCodesFrame();
explicit EventTimingCodesFrame();
/*!
/*!
* Construct a event timing codes frame based on the data in \a data.
*/
explicit EventTimingCodesFrame(const ByteVector &data);
explicit EventTimingCodesFrame(const ByteVector &data);
/*!
/*!
* Destroys this EventTimingCodesFrame instance.
*/
virtual ~EventTimingCodesFrame();
virtual ~EventTimingCodesFrame();
/*!
/*!
* Returns a null string.
*/
virtual String toString() const;
virtual String toString() const;
/*!
/*!
* Returns the timestamp format.
*/
TimestampFormat timestampFormat() const;
TimestampFormat timestampFormat() const;
/*!
/*!
* Returns the events with the time stamps.
*/
SynchedEventList synchedEvents() const;
SynchedEventList synchedEvents() const;
/*!
/*!
* Set the timestamp format.
*
* \see timestampFormat()
*/
void setTimestampFormat(TimestampFormat f);
void setTimestampFormat(TimestampFormat f);
/*!
/*!
* Sets the text with the time stamps.
*
* \see text()
*/
void setSynchedEvents(const SynchedEventList &e);
void setSynchedEvents(const SynchedEventList &e);
protected:
// Reimplementations.
protected:
// Reimplementations.
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
private:
/*!
private:
/*!
* The constructor used by the FrameFactory.
*/
EventTimingCodesFrame(const ByteVector &data, Header *h);
EventTimingCodesFrame(const EventTimingCodesFrame &);
EventTimingCodesFrame &operator=(const EventTimingCodesFrame &);
EventTimingCodesFrame(const ByteVector &data, Header *h);
EventTimingCodesFrame(const EventTimingCodesFrame &);
EventTimingCodesFrame &operator=(const EventTimingCodesFrame &);
class EventTimingCodesFramePrivate;
EventTimingCodesFramePrivate *d;
};
class EventTimingCodesFramePrivate;
EventTimingCodesFramePrivate *d;
};
}
}
}
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -34,9 +34,8 @@
using namespace Strawberry_TagLib::TagLib;
using namespace ID3v2;
class GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFramePrivate
{
public:
class GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFramePrivate {
public:
GeneralEncapsulatedObjectFramePrivate() : textEncoding(String::Latin1) {}
String::Type textEncoding;
@@ -50,84 +49,68 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame() :
Frame("GEOB"),
d(new GeneralEncapsulatedObjectFramePrivate())
{
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame() : Frame("GEOB"),
d(new GeneralEncapsulatedObjectFramePrivate()) {
}
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data) :
Frame(data),
d(new GeneralEncapsulatedObjectFramePrivate())
{
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data) : Frame(data),
d(new GeneralEncapsulatedObjectFramePrivate()) {
setData(data);
}
GeneralEncapsulatedObjectFrame::~GeneralEncapsulatedObjectFrame()
{
GeneralEncapsulatedObjectFrame::~GeneralEncapsulatedObjectFrame() {
delete d;
}
String GeneralEncapsulatedObjectFrame::toString() const
{
String GeneralEncapsulatedObjectFrame::toString() const {
String text = "[" + d->mimeType + "]";
if(!d->fileName.isEmpty())
if (!d->fileName.isEmpty())
text += " " + d->fileName;
if(!d->description.isEmpty())
if (!d->description.isEmpty())
text += " \"" + d->description + "\"";
return text;
}
String::Type GeneralEncapsulatedObjectFrame::textEncoding() const
{
String::Type GeneralEncapsulatedObjectFrame::textEncoding() const {
return d->textEncoding;
}
void GeneralEncapsulatedObjectFrame::setTextEncoding(String::Type encoding)
{
void GeneralEncapsulatedObjectFrame::setTextEncoding(String::Type encoding) {
d->textEncoding = encoding;
}
String GeneralEncapsulatedObjectFrame::mimeType() const
{
String GeneralEncapsulatedObjectFrame::mimeType() const {
return d->mimeType;
}
void GeneralEncapsulatedObjectFrame::setMimeType(const String &type)
{
void GeneralEncapsulatedObjectFrame::setMimeType(const String &type) {
d->mimeType = type;
}
String GeneralEncapsulatedObjectFrame::fileName() const
{
String GeneralEncapsulatedObjectFrame::fileName() const {
return d->fileName;
}
void GeneralEncapsulatedObjectFrame::setFileName(const String &name)
{
void GeneralEncapsulatedObjectFrame::setFileName(const String &name) {
d->fileName = name;
}
String GeneralEncapsulatedObjectFrame::description() const
{
String GeneralEncapsulatedObjectFrame::description() const {
return d->description;
}
void GeneralEncapsulatedObjectFrame::setDescription(const String &desc)
{
void GeneralEncapsulatedObjectFrame::setDescription(const String &desc) {
d->description = desc;
}
ByteVector GeneralEncapsulatedObjectFrame::object() const
{
ByteVector GeneralEncapsulatedObjectFrame::object() const {
return d->data;
}
void GeneralEncapsulatedObjectFrame::setObject(const ByteVector &data)
{
void GeneralEncapsulatedObjectFrame::setObject(const ByteVector &data) {
d->data = data;
}
@@ -135,9 +118,8 @@ void GeneralEncapsulatedObjectFrame::setObject(const ByteVector &data)
// protected members
////////////////////////////////////////////////////////////////////////////////
void GeneralEncapsulatedObjectFrame::parseFields(const ByteVector &data)
{
if(data.size() < 4) {
void GeneralEncapsulatedObjectFrame::parseFields(const ByteVector &data) {
if (data.size() < 4) {
debug("An object frame must contain at least 4 bytes.");
return;
}
@@ -153,8 +135,7 @@ void GeneralEncapsulatedObjectFrame::parseFields(const ByteVector &data)
d->data = data.mid(pos);
}
ByteVector GeneralEncapsulatedObjectFrame::renderFields() const
{
ByteVector GeneralEncapsulatedObjectFrame::renderFields() const {
StringList sl;
sl.append(d->fileName);
sl.append(d->description);
@@ -179,9 +160,7 @@ ByteVector GeneralEncapsulatedObjectFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new GeneralEncapsulatedObjectFramePrivate())
{
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data, Header *h) : Frame(h),
d(new GeneralEncapsulatedObjectFramePrivate()) {
parseFields(fieldData(data));
}

View File

@@ -36,11 +36,11 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
namespace ID3v2 {
//! An ID3v2 general encapsulated object frame implementation
//! An ID3v2 general encapsulated object frame implementation
/*!
/*!
* This is an implementation of ID3v2 general encapsulated objects.
* Arbitrary binary data may be included in tags, stored in GEOB frames.
* There may be multiple GEOB frames in a single tag. Each GEOB it
@@ -49,79 +49,77 @@ namespace TagLib {
* uniquely identifies the GEOB frame in the tag.
*/
class TAGLIB_EXPORT GeneralEncapsulatedObjectFrame : public Frame
{
friend class FrameFactory;
class TAGLIB_EXPORT GeneralEncapsulatedObjectFrame : public Frame {
friend class FrameFactory;
public:
/*!
public:
/*!
* Constructs an empty object frame. The description, file name and text
* encoding should be set manually.
*/
GeneralEncapsulatedObjectFrame();
GeneralEncapsulatedObjectFrame();
/*!
/*!
* Constructs a GeneralEncapsulatedObjectFrame frame based on \a data.
*
* \warning This is \em not data for the encapsulated object, for that use
* setObject(). This constructor is used when reading the frame from the
* disk.
*/
explicit GeneralEncapsulatedObjectFrame(const ByteVector &data);
explicit GeneralEncapsulatedObjectFrame(const ByteVector &data);
/*!
/*!
* Destroys the GeneralEncapsulatedObjectFrame instance.
*/
virtual ~GeneralEncapsulatedObjectFrame();
virtual ~GeneralEncapsulatedObjectFrame();
/*!
/*!
* Returns a string containing the description, file name and mime-type
*/
virtual String toString() const;
virtual String toString() const;
/*!
/*!
* Returns the text encoding used for the description and file name.
*
* \see setTextEncoding()
* \see description()
* \see fileName()
*/
String::Type textEncoding() const;
String::Type textEncoding() const;
/*!
/*!
* Set the text encoding used for the description and file name.
*
* \see description()
* \see fileName()
*/
void setTextEncoding(String::Type encoding);
void setTextEncoding(String::Type encoding);
/*!
/*!
* Returns the mime type of the object.
*/
String mimeType() const;
String mimeType() const;
/*!
/*!
* Sets the mime type of the object.
*/
void setMimeType(const String &type);
void setMimeType(const String &type);
/*!
/*!
* Returns the file name of the object.
*
* \see setFileName()
*/
String fileName() const;
String fileName() const;
/*!
/*!
* Sets the file name for the object.
*
* \see fileName()
*/
void setFileName(const String &name);
void setFileName(const String &name);
/*!
/*!
* Returns the content description of the object.
*
* \see setDescription()
@@ -129,9 +127,9 @@ namespace TagLib {
* \see setTextEncoding()
*/
String description() const;
String description() const;
/*!
/*!
* Sets the content description of the object to \a desc.
*
* \see description()
@@ -139,9 +137,9 @@ namespace TagLib {
* \see setTextEncoding()
*/
void setDescription(const String &desc);
void setDescription(const String &desc);
/*!
/*!
* Returns the object data as a ByteVector.
*
* \note ByteVector has a data() method that returns a const char * which
@@ -150,9 +148,9 @@ namespace TagLib {
* \see setObject()
* \see mimeType()
*/
ByteVector object() const;
ByteVector object() const;
/*!
/*!
* Sets the object data to \a data. \a data should be of the type specified in
* this frame's mime-type specification.
*
@@ -160,22 +158,22 @@ namespace TagLib {
* \see mimeType()
* \see setMimeType()
*/
void setObject(const ByteVector &object);
void setObject(const ByteVector &object);
protected:
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
protected:
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
private:
GeneralEncapsulatedObjectFrame(const ByteVector &data, Header *h);
GeneralEncapsulatedObjectFrame(const GeneralEncapsulatedObjectFrame &);
GeneralEncapsulatedObjectFrame &operator=(const GeneralEncapsulatedObjectFrame &);
private:
GeneralEncapsulatedObjectFrame(const ByteVector &data, Header *h);
GeneralEncapsulatedObjectFrame(const GeneralEncapsulatedObjectFrame &);
GeneralEncapsulatedObjectFrame &operator=(const GeneralEncapsulatedObjectFrame &);
class GeneralEncapsulatedObjectFramePrivate;
GeneralEncapsulatedObjectFramePrivate *d;
};
}
}
}
class GeneralEncapsulatedObjectFramePrivate;
GeneralEncapsulatedObjectFramePrivate *d;
};
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -32,9 +32,8 @@
using namespace Strawberry_TagLib::TagLib;
using namespace ID3v2;
class OwnershipFrame::OwnershipFramePrivate
{
public:
class OwnershipFrame::OwnershipFramePrivate {
public:
String pricePaid;
String datePurchased;
String seller;
@@ -45,67 +44,53 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
OwnershipFrame::OwnershipFrame(String::Type encoding) :
Frame("OWNE"),
d(new OwnershipFramePrivate())
{
OwnershipFrame::OwnershipFrame(String::Type encoding) : Frame("OWNE"),
d(new OwnershipFramePrivate()) {
d->textEncoding = encoding;
}
OwnershipFrame::OwnershipFrame(const ByteVector &data) :
Frame(data),
d(new OwnershipFramePrivate())
{
OwnershipFrame::OwnershipFrame(const ByteVector &data) : Frame(data),
d(new OwnershipFramePrivate()) {
setData(data);
}
OwnershipFrame::~OwnershipFrame()
{
OwnershipFrame::~OwnershipFrame() {
delete d;
}
String OwnershipFrame::toString() const
{
String OwnershipFrame::toString() const {
return "pricePaid=" + d->pricePaid + " datePurchased=" + d->datePurchased + " seller=" + d->seller;
}
String OwnershipFrame::pricePaid() const
{
String OwnershipFrame::pricePaid() const {
return d->pricePaid;
}
void OwnershipFrame::setPricePaid(const String &s)
{
void OwnershipFrame::setPricePaid(const String &s) {
d->pricePaid = s;
}
String OwnershipFrame::datePurchased() const
{
String OwnershipFrame::datePurchased() const {
return d->datePurchased;
}
void OwnershipFrame::setDatePurchased(const String &s)
{
void OwnershipFrame::setDatePurchased(const String &s) {
d->datePurchased = s;
}
String OwnershipFrame::seller() const
{
String OwnershipFrame::seller() const {
return d->seller;
}
void OwnershipFrame::setSeller(const String &s)
{
void OwnershipFrame::setSeller(const String &s) {
d->seller = s;
}
String::Type OwnershipFrame::textEncoding() const
{
String::Type OwnershipFrame::textEncoding() const {
return d->textEncoding;
}
void OwnershipFrame::setTextEncoding(String::Type encoding)
{
void OwnershipFrame::setTextEncoding(String::Type encoding) {
d->textEncoding = encoding;
}
@@ -113,8 +98,7 @@ void OwnershipFrame::setTextEncoding(String::Type encoding)
// protected members
////////////////////////////////////////////////////////////////////////////////
void OwnershipFrame::parseFields(const ByteVector &data)
{
void OwnershipFrame::parseFields(const ByteVector &data) {
int pos = 0;
// Get the text encoding
@@ -126,7 +110,7 @@ void OwnershipFrame::parseFields(const ByteVector &data)
// If we don't have at least 8 bytes left then don't parse the rest of the
// data
if(data.size() - pos < 8) {
if (data.size() - pos < 8) {
return;
}
@@ -135,14 +119,13 @@ void OwnershipFrame::parseFields(const ByteVector &data)
pos += 8;
// Read the seller
if(d->textEncoding == String::Latin1)
if (d->textEncoding == String::Latin1)
d->seller = Tag::latin1StringHandler()->parse(data.mid(pos));
else
d->seller = String(data.mid(pos), d->textEncoding);
}
ByteVector OwnershipFrame::renderFields() const
{
ByteVector OwnershipFrame::renderFields() const {
StringList sl;
sl.append(d->seller);
@@ -163,9 +146,7 @@ ByteVector OwnershipFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
OwnershipFrame::OwnershipFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new OwnershipFramePrivate())
{
OwnershipFrame::OwnershipFrame(const ByteVector &data, Header *h) : Frame(h),
d(new OwnershipFramePrivate()) {
parseFields(fieldData(data));
}

View File

@@ -32,85 +32,84 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
namespace ID3v2 {
//! An implementation of ID3v2 "ownership"
//! An implementation of ID3v2 "ownership"
/*!
/*!
* This implements the ID3v2 ownership (OWNE frame). It consists of
* a price paid, a date purchased (YYYYMMDD) and the name of the seller.
*/
class TAGLIB_EXPORT OwnershipFrame : public Frame
{
friend class FrameFactory;
class TAGLIB_EXPORT OwnershipFrame : public Frame {
friend class FrameFactory;
public:
/*!
public:
/*!
* Construct an empty ownership frame.
*/
explicit OwnershipFrame(String::Type encoding = String::Latin1);
explicit OwnershipFrame(String::Type encoding = String::Latin1);
/*!
/*!
* Construct a ownership based on the data in \a data.
*/
explicit OwnershipFrame(const ByteVector &data);
explicit OwnershipFrame(const ByteVector &data);
/*!
/*!
* Destroys this OwnershipFrame instance.
*/
virtual ~OwnershipFrame();
virtual ~OwnershipFrame();
/*!
/*!
* Returns the text of this popularimeter.
*
* \see text()
*/
virtual String toString() const;
virtual String toString() const;
/*!
/*!
* Returns the date purchased.
*
* \see setDatePurchased()
*/
String datePurchased() const;
String datePurchased() const;
/*!
/*!
* Set the date purchased.
*
* \see datePurchased()
*/
void setDatePurchased(const String &datePurchased);
void setDatePurchased(const String &datePurchased);
/*!
/*!
* Returns the price paid.
*
* \see setPricePaid()
*/
String pricePaid() const;
String pricePaid() const;
/*!
/*!
* Set the price paid.
*
* \see pricePaid()
*/
void setPricePaid(const String &pricePaid);
void setPricePaid(const String &pricePaid);
/*!
/*!
* Returns the seller.
*
* \see setSeller()
*/
String seller() const;
String seller() const;
/*!
/*!
* Set the seller.
*
* \see seller()
*/
void setSeller(const String &seller);
void setSeller(const String &seller);
/*!
/*!
* Returns the text encoding that will be used in rendering this frame.
* This defaults to the type that was either specified in the constructor
* or read from the frame when parsed.
@@ -118,36 +117,36 @@ namespace TagLib {
* \see setTextEncoding()
* \see render()
*/
String::Type textEncoding() const;
String::Type textEncoding() const;
/*!
/*!
* Sets the text encoding to be used when rendering this frame to
* \a encoding.
*
* \see textEncoding()
* \see render()
*/
void setTextEncoding(String::Type encoding);
void setTextEncoding(String::Type encoding);
protected:
// Reimplementations.
protected:
// Reimplementations.
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
private:
/*!
private:
/*!
* The constructor used by the FrameFactory.
*/
OwnershipFrame(const ByteVector &data, Header *h);
OwnershipFrame(const OwnershipFrame &);
OwnershipFrame &operator=(const OwnershipFrame &);
OwnershipFrame(const ByteVector &data, Header *h);
OwnershipFrame(const OwnershipFrame &);
OwnershipFrame &operator=(const OwnershipFrame &);
class OwnershipFramePrivate;
OwnershipFramePrivate *d;
};
class OwnershipFramePrivate;
OwnershipFramePrivate *d;
};
}
}
}
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -28,9 +28,8 @@
using namespace Strawberry_TagLib::TagLib;
using namespace ID3v2;
class PodcastFrame::PodcastFramePrivate
{
public:
class PodcastFrame::PodcastFramePrivate {
public:
ByteVector fieldData;
};
@@ -38,20 +37,16 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
PodcastFrame::PodcastFrame() :
Frame("PCST"),
d(new PodcastFramePrivate())
{
PodcastFrame::PodcastFrame() : Frame("PCST"),
d(new PodcastFramePrivate()) {
d->fieldData = ByteVector(4, '\0');
}
PodcastFrame::~PodcastFrame()
{
PodcastFrame::~PodcastFrame() {
delete d;
}
String PodcastFrame::toString() const
{
String PodcastFrame::toString() const {
return String();
}
@@ -59,13 +54,11 @@ String PodcastFrame::toString() const
// protected members
////////////////////////////////////////////////////////////////////////////////
void PodcastFrame::parseFields(const ByteVector &data)
{
void PodcastFrame::parseFields(const ByteVector &data) {
d->fieldData = data;
}
ByteVector PodcastFrame::renderFields() const
{
ByteVector PodcastFrame::renderFields() const {
return d->fieldData;
}
@@ -73,9 +66,7 @@ ByteVector PodcastFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
PodcastFrame::PodcastFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new PodcastFramePrivate())
{
PodcastFrame::PodcastFrame(const ByteVector &data, Header *h) : Frame(h),
d(new PodcastFramePrivate()) {
parseFields(fieldData(data));
}

View File

@@ -32,51 +32,50 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
namespace ID3v2 {
//! ID3v2 podcast frame
/*!
//! ID3v2 podcast frame
/*!
* An implementation of ID3v2 podcast flag, a frame with four zero bytes.
*/
class TAGLIB_EXPORT PodcastFrame : public Frame
{
friend class FrameFactory;
class TAGLIB_EXPORT PodcastFrame : public Frame {
friend class FrameFactory;
public:
/*!
public:
/*!
* Construct a podcast frame.
*/
PodcastFrame();
PodcastFrame();
/*!
/*!
* Destroys this PodcastFrame instance.
*/
virtual ~PodcastFrame();
virtual ~PodcastFrame();
/*!
/*!
* Returns a null string.
*/
virtual String toString() const;
virtual String toString() const;
protected:
// Reimplementations.
protected:
// Reimplementations.
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
private:
/*!
private:
/*!
* The constructor used by the FrameFactory.
*/
PodcastFrame(const ByteVector &data, Header *h);
PodcastFrame(const PodcastFrame &);
PodcastFrame &operator=(const PodcastFrame &);
PodcastFrame(const ByteVector &data, Header *h);
PodcastFrame(const PodcastFrame &);
PodcastFrame &operator=(const PodcastFrame &);
class PodcastFramePrivate;
PodcastFramePrivate *d;
};
class PodcastFramePrivate;
PodcastFramePrivate *d;
};
}
}
}
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -30,9 +30,8 @@
using namespace Strawberry_TagLib::TagLib;
using namespace ID3v2;
class PopularimeterFrame::PopularimeterFramePrivate
{
public:
class PopularimeterFrame::PopularimeterFramePrivate {
public:
PopularimeterFramePrivate() : rating(0), counter(0) {}
String email;
int rating;
@@ -43,56 +42,44 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
PopularimeterFrame::PopularimeterFrame() :
Frame("POPM"),
d(new PopularimeterFramePrivate())
{
PopularimeterFrame::PopularimeterFrame() : Frame("POPM"),
d(new PopularimeterFramePrivate()) {
}
PopularimeterFrame::PopularimeterFrame(const ByteVector &data) :
Frame(data),
d(new PopularimeterFramePrivate())
{
PopularimeterFrame::PopularimeterFrame(const ByteVector &data) : Frame(data),
d(new PopularimeterFramePrivate()) {
setData(data);
}
PopularimeterFrame::~PopularimeterFrame()
{
PopularimeterFrame::~PopularimeterFrame() {
delete d;
}
String PopularimeterFrame::toString() const
{
String PopularimeterFrame::toString() const {
return d->email + " rating=" + String::number(d->rating) + " counter=" + String::number(d->counter);
}
String PopularimeterFrame::email() const
{
String PopularimeterFrame::email() const {
return d->email;
}
void PopularimeterFrame::setEmail(const String &s)
{
void PopularimeterFrame::setEmail(const String &s) {
d->email = s;
}
int PopularimeterFrame::rating() const
{
int PopularimeterFrame::rating() const {
return d->rating;
}
void PopularimeterFrame::setRating(int s)
{
void PopularimeterFrame::setRating(int s) {
d->rating = s;
}
unsigned int PopularimeterFrame::counter() const
{
unsigned int PopularimeterFrame::counter() const {
return d->counter;
}
void PopularimeterFrame::setCounter(unsigned int s)
{
void PopularimeterFrame::setCounter(unsigned int s) {
d->counter = s;
}
@@ -100,24 +87,22 @@ void PopularimeterFrame::setCounter(unsigned int s)
// protected members
////////////////////////////////////////////////////////////////////////////////
void PopularimeterFrame::parseFields(const ByteVector &data)
{
void PopularimeterFrame::parseFields(const ByteVector &data) {
int pos = 0, size = int(data.size());
d->email = readStringField(data, String::Latin1, &pos);
d->rating = 0;
d->counter = 0;
if(pos < size) {
if (pos < size) {
d->rating = (unsigned char)(data[pos++]);
if(pos < size) {
if (pos < size) {
d->counter = data.toUInt(static_cast<unsigned int>(pos));
}
}
}
ByteVector PopularimeterFrame::renderFields() const
{
ByteVector PopularimeterFrame::renderFields() const {
ByteVector data;
data.append(d->email.data(String::Latin1));
@@ -132,9 +117,7 @@ ByteVector PopularimeterFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
PopularimeterFrame::PopularimeterFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new PopularimeterFramePrivate())
{
PopularimeterFrame::PopularimeterFrame(const ByteVector &data, Header *h) : Frame(h),
d(new PopularimeterFramePrivate()) {
parseFields(fieldData(data));
}

View File

@@ -32,103 +32,102 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
namespace ID3v2 {
//! An implementation of ID3v2 "popularimeter"
//! An implementation of ID3v2 "popularimeter"
/*!
/*!
* This implements the ID3v2 popularimeter (POPM frame). It consists of
* an email, a rating and an optional counter.
*/
class TAGLIB_EXPORT PopularimeterFrame : public Frame
{
friend class FrameFactory;
class TAGLIB_EXPORT PopularimeterFrame : public Frame {
friend class FrameFactory;
public:
/*!
public:
/*!
* Construct an empty popularimeter frame.
*/
explicit PopularimeterFrame();
explicit PopularimeterFrame();
/*!
/*!
* Construct a popularimeter based on the data in \a data.
*/
explicit PopularimeterFrame(const ByteVector &data);
explicit PopularimeterFrame(const ByteVector &data);
/*!
/*!
* Destroys this PopularimeterFrame instance.
*/
virtual ~PopularimeterFrame();
virtual ~PopularimeterFrame();
/*!
/*!
* Returns the text of this popularimeter.
*
* \see text()
*/
virtual String toString() const;
virtual String toString() const;
/*!
/*!
* Returns the email.
*
* \see setEmail()
*/
String email() const;
String email() const;
/*!
/*!
* Set the email.
*
* \see email()
*/
void setEmail(const String &email);
void setEmail(const String &email);
/*!
/*!
* Returns the rating.
*
* \see setRating()
*/
int rating() const;
int rating() const;
/*!
/*!
* Set the rating.
*
* \see rating()
*/
void setRating(int rating);
void setRating(int rating);
/*!
/*!
* Returns the counter.
*
* \see setCounter()
*/
unsigned int counter() const;
unsigned int counter() const;
/*!
/*!
* Set the counter.
*
* \see counter()
*/
void setCounter(unsigned int counter);
void setCounter(unsigned int counter);
protected:
// Reimplementations.
protected:
// Reimplementations.
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
private:
/*!
private:
/*!
* The constructor used by the FrameFactory.
*/
PopularimeterFrame(const ByteVector &data, Header *h);
PopularimeterFrame(const PopularimeterFrame &);
PopularimeterFrame &operator=(const PopularimeterFrame &);
PopularimeterFrame(const ByteVector &data, Header *h);
PopularimeterFrame(const PopularimeterFrame &);
PopularimeterFrame &operator=(const PopularimeterFrame &);
class PopularimeterFramePrivate;
PopularimeterFramePrivate *d;
};
class PopularimeterFramePrivate;
PopularimeterFramePrivate *d;
};
}
}
}
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -34,9 +34,8 @@ using namespace Strawberry_TagLib::TagLib;
using namespace ID3v2;
class PrivateFrame::PrivateFramePrivate
{
public:
class PrivateFrame::PrivateFramePrivate {
public:
ByteVector data;
String owner;
};
@@ -45,46 +44,36 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
PrivateFrame::PrivateFrame() :
Frame("PRIV"),
d(new PrivateFramePrivate())
{
PrivateFrame::PrivateFrame() : Frame("PRIV"),
d(new PrivateFramePrivate()) {
}
PrivateFrame::PrivateFrame(const ByteVector &data) :
Frame(data),
d(new PrivateFramePrivate())
{
PrivateFrame::PrivateFrame(const ByteVector &data) : Frame(data),
d(new PrivateFramePrivate()) {
setData(data);
}
PrivateFrame::~PrivateFrame()
{
PrivateFrame::~PrivateFrame() {
delete d;
}
String PrivateFrame::toString() const
{
String PrivateFrame::toString() const {
return d->owner;
}
String PrivateFrame::owner() const
{
String PrivateFrame::owner() const {
return d->owner;
}
ByteVector PrivateFrame::data() const
{
ByteVector PrivateFrame::data() const {
return d->data;
}
void PrivateFrame::setOwner(const String &s)
{
void PrivateFrame::setOwner(const String &s) {
d->owner = s;
}
void PrivateFrame::setData(const ByteVector & data)
{
void PrivateFrame::setData(const ByteVector &data) {
d->data = data;
}
@@ -92,24 +81,22 @@ void PrivateFrame::setData(const ByteVector & data)
// protected members
////////////////////////////////////////////////////////////////////////////////
void PrivateFrame::parseFields(const ByteVector &data)
{
if(data.size() < 2) {
void PrivateFrame::parseFields(const ByteVector &data) {
if (data.size() < 2) {
debug("A private frame must contain at least 2 bytes.");
return;
}
// Owner identifier is assumed to be Latin1
const int byteAlign = 1;
const int byteAlign = 1;
const int endOfOwner = data.find(textDelimiter(String::Latin1), 0, byteAlign);
d->owner = String(data.mid(0, endOfOwner));
d->owner = String(data.mid(0, endOfOwner));
d->data = data.mid(endOfOwner + 1);
}
ByteVector PrivateFrame::renderFields() const
{
ByteVector PrivateFrame::renderFields() const {
ByteVector v;
v.append(d->owner.data(String::Latin1));
@@ -123,9 +110,7 @@ ByteVector PrivateFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
PrivateFrame::PrivateFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new PrivateFramePrivate())
{
PrivateFrame::PrivateFrame(const ByteVector &data, Header *h) : Frame(h),
d(new PrivateFramePrivate()) {
parseFields(fieldData(data));
}

View File

@@ -33,81 +33,80 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
namespace ID3v2 {
//! An implementation of ID3v2 privateframe
//! An implementation of ID3v2 privateframe
class TAGLIB_EXPORT PrivateFrame : public Frame
{
friend class FrameFactory;
class TAGLIB_EXPORT PrivateFrame : public Frame {
friend class FrameFactory;
public:
/*!
public:
/*!
* Construct an empty private frame.
*/
PrivateFrame();
PrivateFrame();
/*!
/*!
* Construct a private frame based on the data in \a data.
*
* \note This is the constructor used when parsing the frame from a file.
*/
explicit PrivateFrame(const ByteVector &data);
explicit PrivateFrame(const ByteVector &data);
/*!
/*!
* Destroys this private frame instance.
*/
virtual ~PrivateFrame();
virtual ~PrivateFrame();
/*!
/*!
* Returns the text of this private frame, currently just the owner.
*
* \see text()
*/
virtual String toString() const;
virtual String toString() const;
/*!
/*!
* \return The owner of the private frame.
* \note This should contain an email address or link to a website.
*/
String owner() const;
String owner() const;
/*!
/*!
*
*/
ByteVector data() const;
ByteVector data() const;
/*!
/*!
* Sets the owner of the frame to \a s.
* \note This should contain an email address or link to a website.
*/
void setOwner(const String &s);
void setOwner(const String &s);
/*!
/*!
*
*/
void setData(const ByteVector &v);
void setData(const ByteVector &v);
protected:
// Reimplementations.
protected:
// Reimplementations.
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
private:
/*!
private:
/*!
* The constructor used by the FrameFactory.
*/
PrivateFrame(const ByteVector &data, Header *h);
PrivateFrame(const ByteVector &data, Header *h);
PrivateFrame(const PrivateFrame &);
PrivateFrame &operator=(const PrivateFrame &);
PrivateFrame(const PrivateFrame &);
PrivateFrame &operator=(const PrivateFrame &);
class PrivateFramePrivate;
PrivateFramePrivate *d;
};
class PrivateFramePrivate;
PrivateFramePrivate *d;
};
}
}
}
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -31,8 +31,7 @@
using namespace Strawberry_TagLib::TagLib;
using namespace ID3v2;
struct ChannelData
{
struct ChannelData {
ChannelData() : channelType(RelativeVolumeFrame::Other), volumeAdjustment(0) {}
RelativeVolumeFrame::ChannelType channelType;
@@ -40,9 +39,8 @@ struct ChannelData
RelativeVolumeFrame::PeakVolume peakVolume;
};
class RelativeVolumeFrame::RelativeVolumeFramePrivate
{
public:
class RelativeVolumeFrame::RelativeVolumeFramePrivate {
public:
String identification;
Map<ChannelType, ChannelData> channels;
};
@@ -51,35 +49,28 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
RelativeVolumeFrame::RelativeVolumeFrame() :
Frame("RVA2"),
d(new RelativeVolumeFramePrivate())
{
RelativeVolumeFrame::RelativeVolumeFrame() : Frame("RVA2"),
d(new RelativeVolumeFramePrivate()) {
}
RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data) :
Frame(data),
d(new RelativeVolumeFramePrivate())
{
RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data) : Frame(data),
d(new RelativeVolumeFramePrivate()) {
setData(data);
}
RelativeVolumeFrame::~RelativeVolumeFrame()
{
RelativeVolumeFrame::~RelativeVolumeFrame() {
delete d;
}
String RelativeVolumeFrame::toString() const
{
String RelativeVolumeFrame::toString() const {
return d->identification;
}
List<RelativeVolumeFrame::ChannelType> RelativeVolumeFrame::channels() const
{
List<RelativeVolumeFrame::ChannelType> RelativeVolumeFrame::channels() const {
List<ChannelType> l;
Map<ChannelType, ChannelData>::ConstIterator it = d->channels.begin();
for(; it != d->channels.end(); ++it)
for (; it != d->channels.end(); ++it)
l.append((*it).first);
return l;
@@ -87,85 +78,68 @@ List<RelativeVolumeFrame::ChannelType> RelativeVolumeFrame::channels() const
// deprecated
RelativeVolumeFrame::ChannelType RelativeVolumeFrame::channelType() const
{
RelativeVolumeFrame::ChannelType RelativeVolumeFrame::channelType() const {
return MasterVolume;
}
// deprecated
void RelativeVolumeFrame::setChannelType(ChannelType)
{
void RelativeVolumeFrame::setChannelType(ChannelType) {
}
short RelativeVolumeFrame::volumeAdjustmentIndex(ChannelType type) const
{
short RelativeVolumeFrame::volumeAdjustmentIndex(ChannelType type) const {
return d->channels.contains(type) ? d->channels[type].volumeAdjustment : 0;
}
short RelativeVolumeFrame::volumeAdjustmentIndex() const
{
short RelativeVolumeFrame::volumeAdjustmentIndex() const {
return volumeAdjustmentIndex(MasterVolume);
}
void RelativeVolumeFrame::setVolumeAdjustmentIndex(short index, ChannelType type)
{
void RelativeVolumeFrame::setVolumeAdjustmentIndex(short index, ChannelType type) {
d->channels[type].volumeAdjustment = index;
}
void RelativeVolumeFrame::setVolumeAdjustmentIndex(short index)
{
void RelativeVolumeFrame::setVolumeAdjustmentIndex(short index) {
setVolumeAdjustmentIndex(index, MasterVolume);
}
float RelativeVolumeFrame::volumeAdjustment(ChannelType type) const
{
float RelativeVolumeFrame::volumeAdjustment(ChannelType type) const {
return d->channels.contains(type) ? float(d->channels[type].volumeAdjustment) / float(512) : 0;
}
float RelativeVolumeFrame::volumeAdjustment() const
{
float RelativeVolumeFrame::volumeAdjustment() const {
return volumeAdjustment(MasterVolume);
}
void RelativeVolumeFrame::setVolumeAdjustment(float adjustment, ChannelType type)
{
void RelativeVolumeFrame::setVolumeAdjustment(float adjustment, ChannelType type) {
d->channels[type].volumeAdjustment = short(adjustment * float(512));
}
void RelativeVolumeFrame::setVolumeAdjustment(float adjustment)
{
void RelativeVolumeFrame::setVolumeAdjustment(float adjustment) {
setVolumeAdjustment(adjustment, MasterVolume);
}
RelativeVolumeFrame::PeakVolume RelativeVolumeFrame::peakVolume(ChannelType type) const
{
RelativeVolumeFrame::PeakVolume RelativeVolumeFrame::peakVolume(ChannelType type) const {
return d->channels.contains(type) ? d->channels[type].peakVolume : PeakVolume();
}
RelativeVolumeFrame::PeakVolume RelativeVolumeFrame::peakVolume() const
{
RelativeVolumeFrame::PeakVolume RelativeVolumeFrame::peakVolume() const {
return peakVolume(MasterVolume);
}
void RelativeVolumeFrame::setPeakVolume(const PeakVolume &peak, ChannelType type)
{
void RelativeVolumeFrame::setPeakVolume(const PeakVolume &peak, ChannelType type) {
d->channels[type].peakVolume = peak;
}
void RelativeVolumeFrame::setPeakVolume(const PeakVolume &peak)
{
void RelativeVolumeFrame::setPeakVolume(const PeakVolume &peak) {
setPeakVolume(peak, MasterVolume);
}
String RelativeVolumeFrame::identification() const
{
String RelativeVolumeFrame::identification() const {
return d->identification;
}
void RelativeVolumeFrame::setIdentification(const String &s)
{
void RelativeVolumeFrame::setIdentification(const String &s) {
d->identification = s;
}
@@ -173,14 +147,13 @@ void RelativeVolumeFrame::setIdentification(const String &s)
// protected members
////////////////////////////////////////////////////////////////////////////////
void RelativeVolumeFrame::parseFields(const ByteVector &data)
{
void RelativeVolumeFrame::parseFields(const ByteVector &data) {
int pos = 0;
d->identification = readStringField(data, String::Latin1, &pos);
// Each channel is at least 4 bytes.
while(pos <= (int)data.size() - 4) {
while (pos <= (int)data.size() - 4) {
ChannelType type = ChannelType(data[pos]);
pos += 1;
@@ -199,8 +172,7 @@ void RelativeVolumeFrame::parseFields(const ByteVector &data)
}
}
ByteVector RelativeVolumeFrame::renderFields() const
{
ByteVector RelativeVolumeFrame::renderFields() const {
ByteVector data;
data.append(d->identification.data(String::Latin1));
@@ -208,7 +180,7 @@ ByteVector RelativeVolumeFrame::renderFields() const
Map<ChannelType, ChannelData>::ConstIterator it = d->channels.begin();
for(; it != d->channels.end(); ++it) {
for (; it != d->channels.end(); ++it) {
ChannelType type = (*it).first;
const ChannelData &channel = (*it).second;
@@ -225,9 +197,7 @@ ByteVector RelativeVolumeFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new RelativeVolumeFramePrivate())
{
RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data, Header *h) : Frame(h),
d(new RelativeVolumeFramePrivate()) {
parseFields(fieldData(data));
}

View File

@@ -33,11 +33,11 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
namespace ID3v2 {
//! An ID3v2 relative volume adjustment frame implementation
//! An ID3v2 relative volume adjustment frame implementation
/*!
/*!
* This is an implementation of ID3v2 relative volume adjustment. The
* presence of this frame makes it possible to specify an increase in volume
* for an audio file or specific audio tracks in that file.
@@ -47,99 +47,96 @@ namespace TagLib {
* different channel types.
*/
class TAGLIB_EXPORT RelativeVolumeFrame : public Frame
{
friend class FrameFactory;
class TAGLIB_EXPORT RelativeVolumeFrame : public Frame {
friend class FrameFactory;
public:
/*!
public:
/*!
* This indicates the type of volume adjustment that should be applied.
*/
enum ChannelType {
//! A type not enumerated below
Other = 0x00,
//! The master volume for the track
MasterVolume = 0x01,
//! The front right audio channel
FrontRight = 0x02,
//! The front left audio channel
FrontLeft = 0x03,
//! The back right audio channel
BackRight = 0x04,
//! The back left audio channel
BackLeft = 0x05,
//! The front center audio channel
FrontCentre = 0x06,
//! The back center audio channel
BackCentre = 0x07,
//! The subwoofer audio channel
Subwoofer = 0x08
};
enum ChannelType {
//! A type not enumerated below
Other = 0x00,
//! The master volume for the track
MasterVolume = 0x01,
//! The front right audio channel
FrontRight = 0x02,
//! The front left audio channel
FrontLeft = 0x03,
//! The back right audio channel
BackRight = 0x04,
//! The back left audio channel
BackLeft = 0x05,
//! The front center audio channel
FrontCentre = 0x06,
//! The back center audio channel
BackCentre = 0x07,
//! The subwoofer audio channel
Subwoofer = 0x08
};
//! Struct that stores the relevant values for ID3v2 peak volume
//! Struct that stores the relevant values for ID3v2 peak volume
/*!
/*!
* The peak volume is described as a series of bits that is padded to fill
* a block of bytes. These two values should always be updated in tandem.
*/
struct PeakVolume
{
/*!
struct PeakVolume {
/*!
* Constructs an empty peak volume description.
*/
PeakVolume() : bitsRepresentingPeak(0) {}
/*!
PeakVolume() : bitsRepresentingPeak(0) {}
/*!
* The number of bits (in the range of 0 to 255) used to describe the
* peak volume.
*/
unsigned char bitsRepresentingPeak;
/*!
unsigned char bitsRepresentingPeak;
/*!
* The array of bits (represented as a series of bytes) used to describe
* the peak volume.
*/
ByteVector peakVolume;
};
ByteVector peakVolume;
};
/*!
/*!
* Constructs a RelativeVolumeFrame. The relevant data should be set
* manually.
*/
RelativeVolumeFrame();
RelativeVolumeFrame();
/*!
/*!
* Constructs a RelativeVolumeFrame based on the contents of \a data.
*/
RelativeVolumeFrame(const ByteVector &data);
RelativeVolumeFrame(const ByteVector &data);
/*!
/*!
* Destroys the RelativeVolumeFrame instance.
*/
virtual ~RelativeVolumeFrame();
virtual ~RelativeVolumeFrame();
/*!
/*!
* Returns the frame's identification.
*
* \see identification()
*/
virtual String toString() const;
virtual String toString() const;
/*!
/*!
* Returns a list of channels with information currently in the frame.
*/
List<ChannelType> channels() const;
List<ChannelType> channels() const;
/*!
/*!
* \deprecated Always returns master volume.
*/
TAGLIB_DEPRECATED ChannelType channelType() const;
TAGLIB_DEPRECATED ChannelType channelType() const;
/*!
/*!
* \deprecated This method no longer has any effect.
*/
TAGLIB_DEPRECATED void setChannelType(ChannelType t);
TAGLIB_DEPRECATED void setChannelType(ChannelType t);
/*
/*
* There was a terrible API goof here, and while this can't be changed to
* the way it appears below for binary compatibility reasons, let's at
* least pretend that it looks clean.
@@ -147,7 +144,7 @@ namespace TagLib {
#ifdef DOXYGEN
/*!
/*!
* Returns the relative volume adjustment "index". As indicated by the
* ID3v2 standard this is a 16-bit signed integer that reflects the
* decibels of adjustment when divided by 512.
@@ -158,9 +155,9 @@ namespace TagLib {
* \see setVolumeAdjustmentIndex()
* \see volumeAjustment()
*/
short volumeAdjustmentIndex(ChannelType type = MasterVolume) const;
short volumeAdjustmentIndex(ChannelType type = MasterVolume) const;
/*!
/*!
* Set the volume adjustment to \a index. As indicated by the ID3v2
* standard this is a 16-bit signed integer that reflects the decibels of
* adjustment when divided by 512.
@@ -170,9 +167,9 @@ namespace TagLib {
* \see volumeAdjustmentIndex()
* \see setVolumeAjustment()
*/
void setVolumeAdjustmentIndex(short index, ChannelType type = MasterVolume);
void setVolumeAdjustmentIndex(short index, ChannelType type = MasterVolume);
/*!
/*!
* Returns the relative volume adjustment in decibels.
*
* \note Because this is actually stored internally as an "index" to this
@@ -185,9 +182,9 @@ namespace TagLib {
* \see setVolumeAdjustment()
* \see volumeAdjustmentIndex()
*/
float volumeAdjustment(ChannelType type = MasterVolume) const;
float volumeAdjustment(ChannelType type = MasterVolume) const;
/*!
/*!
* Set the relative volume adjustment in decibels to \a adjustment.
*
* By default this sets the value for the master volume.
@@ -199,9 +196,9 @@ namespace TagLib {
* \see setVolumeAdjustment()
* \see volumeAdjustmentIndex()
*/
void setVolumeAdjustment(float adjustment, ChannelType type = MasterVolume);
void setVolumeAdjustment(float adjustment, ChannelType type = MasterVolume);
/*!
/*!
* Returns the peak volume (represented as a length and a string of bits).
*
* This defaults to returning the value for the master volume channel if
@@ -209,68 +206,68 @@ namespace TagLib {
*
* \see setPeakVolume()
*/
PeakVolume peakVolume(ChannelType type = MasterVolume) const;
PeakVolume peakVolume(ChannelType type = MasterVolume) const;
/*!
/*!
* Sets the peak volume to \a peak.
*
* By default this sets the value for the master volume.
*
* \see peakVolume()
*/
void setPeakVolume(const PeakVolume &peak, ChannelType type = MasterVolume);
void setPeakVolume(const PeakVolume &peak, ChannelType type = MasterVolume);
#else
// BIC: Combine each of the following pairs of functions (or maybe just
// rework this junk altogether).
// BIC: Combine each of the following pairs of functions (or maybe just
// rework this junk altogether).
short volumeAdjustmentIndex(ChannelType type) const;
short volumeAdjustmentIndex() const;
short volumeAdjustmentIndex(ChannelType type) const;
short volumeAdjustmentIndex() const;
void setVolumeAdjustmentIndex(short index, ChannelType type);
void setVolumeAdjustmentIndex(short index);
void setVolumeAdjustmentIndex(short index, ChannelType type);
void setVolumeAdjustmentIndex(short index);
float volumeAdjustment(ChannelType type) const;
float volumeAdjustment() const;
float volumeAdjustment(ChannelType type) const;
float volumeAdjustment() const;
void setVolumeAdjustment(float adjustment, ChannelType type);
void setVolumeAdjustment(float adjustment);
void setVolumeAdjustment(float adjustment, ChannelType type);
void setVolumeAdjustment(float adjustment);
PeakVolume peakVolume(ChannelType type) const;
PeakVolume peakVolume() const;
PeakVolume peakVolume(ChannelType type) const;
PeakVolume peakVolume() const;
void setPeakVolume(const PeakVolume &peak, ChannelType type);
void setPeakVolume(const PeakVolume &peak);
void setPeakVolume(const PeakVolume &peak, ChannelType type);
void setPeakVolume(const PeakVolume &peak);
#endif
/*!
/*!
* Returns the identification for this frame.
*/
String identification() const;
String identification() const;
/*!
/*!
* Sets the identification of the frame to \a s. The string
* is used to identify the situation and/or device where this
* adjustment should apply.
*/
void setIdentification(const String &s);
void setIdentification(const String &s);
protected:
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
protected:
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
private:
RelativeVolumeFrame(const ByteVector &data, Header *h);
RelativeVolumeFrame(const RelativeVolumeFrame &);
RelativeVolumeFrame &operator=(const RelativeVolumeFrame &);
private:
RelativeVolumeFrame(const ByteVector &data, Header *h);
RelativeVolumeFrame(const RelativeVolumeFrame &);
RelativeVolumeFrame &operator=(const RelativeVolumeFrame &);
class RelativeVolumeFramePrivate;
RelativeVolumeFramePrivate *d;
};
class RelativeVolumeFramePrivate;
RelativeVolumeFramePrivate *d;
};
}
}
}
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -32,13 +32,11 @@
using namespace Strawberry_TagLib::TagLib;
using namespace ID3v2;
class SynchronizedLyricsFrame::SynchronizedLyricsFramePrivate
{
public:
SynchronizedLyricsFramePrivate() :
textEncoding(String::Latin1),
timestampFormat(SynchronizedLyricsFrame::AbsoluteMilliseconds),
type(SynchronizedLyricsFrame::Lyrics) {}
class SynchronizedLyricsFrame::SynchronizedLyricsFramePrivate {
public:
SynchronizedLyricsFramePrivate() : textEncoding(String::Latin1),
timestampFormat(SynchronizedLyricsFrame::AbsoluteMilliseconds),
type(SynchronizedLyricsFrame::Lyrics) {}
String::Type textEncoding;
ByteVector language;
SynchronizedLyricsFrame::TimestampFormat timestampFormat;
@@ -51,90 +49,72 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
SynchronizedLyricsFrame::SynchronizedLyricsFrame(String::Type encoding) :
Frame("SYLT"),
d(new SynchronizedLyricsFramePrivate())
{
SynchronizedLyricsFrame::SynchronizedLyricsFrame(String::Type encoding) : Frame("SYLT"),
d(new SynchronizedLyricsFramePrivate()) {
d->textEncoding = encoding;
}
SynchronizedLyricsFrame::SynchronizedLyricsFrame(const ByteVector &data) :
Frame(data),
d(new SynchronizedLyricsFramePrivate())
{
SynchronizedLyricsFrame::SynchronizedLyricsFrame(const ByteVector &data) : Frame(data),
d(new SynchronizedLyricsFramePrivate()) {
setData(data);
}
SynchronizedLyricsFrame::~SynchronizedLyricsFrame()
{
SynchronizedLyricsFrame::~SynchronizedLyricsFrame() {
delete d;
}
String SynchronizedLyricsFrame::toString() const
{
String SynchronizedLyricsFrame::toString() const {
return d->description;
}
String::Type SynchronizedLyricsFrame::textEncoding() const
{
String::Type SynchronizedLyricsFrame::textEncoding() const {
return d->textEncoding;
}
ByteVector SynchronizedLyricsFrame::language() const
{
ByteVector SynchronizedLyricsFrame::language() const {
return d->language;
}
SynchronizedLyricsFrame::TimestampFormat
SynchronizedLyricsFrame::timestampFormat() const
{
SynchronizedLyricsFrame::timestampFormat() const {
return d->timestampFormat;
}
SynchronizedLyricsFrame::Type SynchronizedLyricsFrame::type() const
{
SynchronizedLyricsFrame::Type SynchronizedLyricsFrame::type() const {
return d->type;
}
String SynchronizedLyricsFrame::description() const
{
String SynchronizedLyricsFrame::description() const {
return d->description;
}
SynchronizedLyricsFrame::SynchedTextList
SynchronizedLyricsFrame::synchedText() const
{
SynchronizedLyricsFrame::synchedText() const {
return d->synchedText;
}
void SynchronizedLyricsFrame::setTextEncoding(String::Type encoding)
{
void SynchronizedLyricsFrame::setTextEncoding(String::Type encoding) {
d->textEncoding = encoding;
}
void SynchronizedLyricsFrame::setLanguage(const ByteVector &languageEncoding)
{
void SynchronizedLyricsFrame::setLanguage(const ByteVector &languageEncoding) {
d->language = languageEncoding.mid(0, 3);
}
void SynchronizedLyricsFrame::setTimestampFormat(SynchronizedLyricsFrame::TimestampFormat f)
{
void SynchronizedLyricsFrame::setTimestampFormat(SynchronizedLyricsFrame::TimestampFormat f) {
d->timestampFormat = f;
}
void SynchronizedLyricsFrame::setType(SynchronizedLyricsFrame::Type t)
{
void SynchronizedLyricsFrame::setType(SynchronizedLyricsFrame::Type t) {
d->type = t;
}
void SynchronizedLyricsFrame::setDescription(const String &s)
{
void SynchronizedLyricsFrame::setDescription(const String &s) {
d->description = s;
}
void SynchronizedLyricsFrame::setSynchedText(
const SynchronizedLyricsFrame::SynchedTextList &t)
{
const SynchronizedLyricsFrame::SynchedTextList &t) {
d->synchedText = t;
}
@@ -142,10 +122,9 @@ void SynchronizedLyricsFrame::setSynchedText(
// protected members
////////////////////////////////////////////////////////////////////////////////
void SynchronizedLyricsFrame::parseFields(const ByteVector &data)
{
void SynchronizedLyricsFrame::parseFields(const ByteVector &data) {
const int end = data.size();
if(end < 7) {
if (end < 7) {
debug("A synchronized lyrics frame must contain at least 7 bytes.");
return;
}
@@ -158,7 +137,7 @@ void SynchronizedLyricsFrame::parseFields(const ByteVector &data)
int pos = 6;
d->description = readStringField(data, d->textEncoding, &pos);
if(pos == 6)
if (pos == 6)
return;
/*
@@ -169,27 +148,28 @@ void SynchronizedLyricsFrame::parseFields(const ByteVector &data)
* case of strings without BOM so that readStringField() will work.
*/
String::Type encWithEndianness = d->textEncoding;
if(d->textEncoding == String::UTF16) {
if (d->textEncoding == String::UTF16) {
unsigned short bom = data.toUShort(6, true);
if(bom == 0xfffe) {
if (bom == 0xfffe) {
encWithEndianness = String::UTF16LE;
} else if(bom == 0xfeff) {
}
else if (bom == 0xfeff) {
encWithEndianness = String::UTF16BE;
}
}
d->synchedText.clear();
while(pos < end) {
while (pos < end) {
String::Type enc = d->textEncoding;
// If a UTF16 string has no BOM, use the encoding found above.
if(enc == String::UTF16 && pos + 1 < end) {
if (enc == String::UTF16 && pos + 1 < end) {
unsigned short bom = data.toUShort(pos, true);
if(bom != 0xfffe && bom != 0xfeff) {
if (bom != 0xfffe && bom != 0xfeff) {
enc = encWithEndianness;
}
}
String text = readStringField(data, enc, &pos);
if(pos + 4 > end)
if (pos + 4 > end)
return;
unsigned int time = data.toUInt(pos, true);
@@ -199,16 +179,15 @@ void SynchronizedLyricsFrame::parseFields(const ByteVector &data)
}
}
ByteVector SynchronizedLyricsFrame::renderFields() const
{
ByteVector SynchronizedLyricsFrame::renderFields() const {
ByteVector v;
String::Type encoding = d->textEncoding;
encoding = checkTextEncoding(d->description, encoding);
for(SynchedTextList::ConstIterator it = d->synchedText.begin();
it != d->synchedText.end();
++it) {
for (SynchedTextList::ConstIterator it = d->synchedText.begin();
it != d->synchedText.end();
++it) {
encoding = checkTextEncoding(it->text, encoding);
}
@@ -218,9 +197,9 @@ ByteVector SynchronizedLyricsFrame::renderFields() const
v.append(char(d->type));
v.append(d->description.data(encoding));
v.append(textDelimiter(encoding));
for(SynchedTextList::ConstIterator it = d->synchedText.begin();
it != d->synchedText.end();
++it) {
for (SynchedTextList::ConstIterator it = d->synchedText.begin();
it != d->synchedText.end();
++it) {
const SynchedText &entry = *it;
v.append(entry.text.data(encoding));
v.append(textDelimiter(encoding));
@@ -234,9 +213,7 @@ ByteVector SynchronizedLyricsFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
SynchronizedLyricsFrame::SynchronizedLyricsFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new SynchronizedLyricsFramePrivate())
{
SynchronizedLyricsFrame::SynchronizedLyricsFrame(const ByteVector &data, Header *h) : Frame(h),
d(new SynchronizedLyricsFramePrivate()) {
parseFields(fieldData(data));
}

View File

@@ -32,94 +32,92 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
namespace ID3v2 {
//! ID3v2 synchronized lyrics frame
/*!
//! ID3v2 synchronized lyrics frame
/*!
* An implementation of ID3v2 synchronized lyrics.
*/
class TAGLIB_EXPORT SynchronizedLyricsFrame : public Frame
{
friend class FrameFactory;
class TAGLIB_EXPORT SynchronizedLyricsFrame : public Frame {
friend class FrameFactory;
public:
/*!
public:
/*!
* Specifies the timestamp format used.
*/
enum TimestampFormat {
//! The timestamp is of unknown format.
Unknown = 0x00,
//! The timestamp represents the number of MPEG frames since
//! the beginning of the audio stream.
AbsoluteMpegFrames = 0x01,
//! The timestamp represents the number of milliseconds since
//! the beginning of the audio stream.
AbsoluteMilliseconds = 0x02
};
enum TimestampFormat {
//! The timestamp is of unknown format.
Unknown = 0x00,
//! The timestamp represents the number of MPEG frames since
//! the beginning of the audio stream.
AbsoluteMpegFrames = 0x01,
//! The timestamp represents the number of milliseconds since
//! the beginning of the audio stream.
AbsoluteMilliseconds = 0x02
};
/*!
/*!
* Specifies the type of text contained.
*/
enum Type {
//! The text is some other type of text.
Other = 0x00,
//! The text contains lyrical data.
Lyrics = 0x01,
//! The text contains a transcription.
TextTranscription = 0x02,
//! The text lists the movements in the piece.
Movement = 0x03,
//! The text describes events that occur.
Events = 0x04,
//! The text contains chord changes that occur in the music.
Chord = 0x05,
//! The text contains trivia or "pop up" information about the media.
Trivia = 0x06,
//! The text contains URLs for relevant webpages.
WebpageUrls = 0x07,
//! The text contains URLs for relevant images.
ImageUrls = 0x08
};
enum Type {
//! The text is some other type of text.
Other = 0x00,
//! The text contains lyrical data.
Lyrics = 0x01,
//! The text contains a transcription.
TextTranscription = 0x02,
//! The text lists the movements in the piece.
Movement = 0x03,
//! The text describes events that occur.
Events = 0x04,
//! The text contains chord changes that occur in the music.
Chord = 0x05,
//! The text contains trivia or "pop up" information about the media.
Trivia = 0x06,
//! The text contains URLs for relevant webpages.
WebpageUrls = 0x07,
//! The text contains URLs for relevant images.
ImageUrls = 0x08
};
/*!
/*!
* Single entry of time stamp and lyrics text.
*/
struct SynchedText {
SynchedText(unsigned int ms, String str) : time(ms), text(str) {}
unsigned int time;
String text;
};
struct SynchedText {
SynchedText(unsigned int ms, String str) : time(ms), text(str) {}
unsigned int time;
String text;
};
/*!
/*!
* List of synchronized lyrics.
*/
typedef Strawberry_TagLib::TagLib::List<SynchedText> SynchedTextList;
typedef Strawberry_TagLib::TagLib::List<SynchedText> SynchedTextList;
/*!
/*!
* Construct an empty synchronized lyrics frame that will use the text
* encoding \a encoding.
*/
explicit SynchronizedLyricsFrame(String::Type encoding = String::Latin1);
explicit SynchronizedLyricsFrame(String::Type encoding = String::Latin1);
/*!
/*!
* Construct a synchronized lyrics frame based on the data in \a data.
*/
explicit SynchronizedLyricsFrame(const ByteVector &data);
explicit SynchronizedLyricsFrame(const ByteVector &data);
/*!
/*!
* Destroys this SynchronizedLyricsFrame instance.
*/
virtual ~SynchronizedLyricsFrame();
virtual ~SynchronizedLyricsFrame();
/*!
/*!
* Returns the description of this synchronized lyrics frame.
*
* \see description()
*/
virtual String toString() const;
virtual String toString() const;
/*!
/*!
* Returns the text encoding that will be used in rendering this frame.
* This defaults to the type that was either specified in the constructor
* or read from the frame when parsed.
@@ -127,9 +125,9 @@ namespace TagLib {
* \see setTextEncoding()
* \see render()
*/
String::Type textEncoding() const;
String::Type textEncoding() const;
/*!
/*!
* Returns the language encoding as a 3 byte encoding as specified by
* <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a>.
*
@@ -137,97 +135,97 @@ namespace TagLib {
*
* \see setLanguage()
*/
ByteVector language() const;
ByteVector language() const;
/*!
/*!
* Returns the timestamp format.
*/
TimestampFormat timestampFormat() const;
TimestampFormat timestampFormat() const;
/*!
/*!
* Returns the type of text contained.
*/
Type type() const;
Type type() const;
/*!
/*!
* Returns the description of this synchronized lyrics frame.
*
* \note Most taggers simply ignore this value.
*
* \see setDescription()
*/
String description() const;
String description() const;
/*!
/*!
* Returns the text with the time stamps.
*/
SynchedTextList synchedText() const;
SynchedTextList synchedText() const;
/*!
/*!
* Sets the text encoding to be used when rendering this frame to
* \a encoding.
*
* \see textEncoding()
* \see render()
*/
void setTextEncoding(String::Type encoding);
void setTextEncoding(String::Type encoding);
/*!
/*!
* Set the language using the 3 byte language code from
* <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a> to
* \a languageCode.
*
* \see language()
*/
void setLanguage(const ByteVector &languageCode);
void setLanguage(const ByteVector &languageCode);
/*!
/*!
* Set the timestamp format.
*
* \see timestampFormat()
*/
void setTimestampFormat(TimestampFormat f);
void setTimestampFormat(TimestampFormat f);
/*!
/*!
* Set the type of text contained.
*
* \see type()
*/
void setType(Type t);
void setType(Type t);
/*!
/*!
* Sets the description of the synchronized lyrics frame to \a s.
*
* \see description()
*/
void setDescription(const String &s);
void setDescription(const String &s);
/*!
/*!
* Sets the text with the time stamps.
*
* \see text()
*/
void setSynchedText(const SynchedTextList &t);
void setSynchedText(const SynchedTextList &t);
protected:
// Reimplementations.
protected:
// Reimplementations.
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
private:
/*!
private:
/*!
* The constructor used by the FrameFactory.
*/
SynchronizedLyricsFrame(const ByteVector &data, Header *h);
SynchronizedLyricsFrame(const SynchronizedLyricsFrame &);
SynchronizedLyricsFrame &operator=(const SynchronizedLyricsFrame &);
SynchronizedLyricsFrame(const ByteVector &data, Header *h);
SynchronizedLyricsFrame(const SynchronizedLyricsFrame &);
SynchronizedLyricsFrame &operator=(const SynchronizedLyricsFrame &);
class SynchronizedLyricsFramePrivate;
SynchronizedLyricsFramePrivate *d;
};
class SynchronizedLyricsFramePrivate;
SynchronizedLyricsFramePrivate *d;
};
}
}
}
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -32,14 +32,11 @@
using namespace Strawberry_TagLib::TagLib;
using namespace ID3v2;
class TableOfContentsFrame::TableOfContentsFramePrivate
{
public:
TableOfContentsFramePrivate() :
tagHeader(0),
isTopLevel(false),
isOrdered(false)
{
class TableOfContentsFrame::TableOfContentsFramePrivate {
public:
TableOfContentsFramePrivate() : tagHeader(0),
isTopLevel(false),
isOrdered(false) {
embeddedFrameList.setAutoDelete(true);
}
@@ -54,146 +51,122 @@ public:
namespace {
// These functions are needed to try to aim for backward compatibility with
// an API that previously (unreasonably) required null bytes to be appended
// at the end of identifiers explicitly by the API user.
// These functions are needed to try to aim for backward compatibility with
// an API that previously (unreasonably) required null bytes to be appended
// at the end of identifiers explicitly by the API user.
// BIC: remove these
// BIC: remove these
ByteVector &strip(ByteVector &b)
{
if(b.endsWith('\0'))
b.resize(b.size() - 1);
return b;
}
ByteVectorList &strip(ByteVectorList &l)
{
for(ByteVectorList::Iterator it = l.begin(); it != l.end(); ++it)
{
strip(*it);
}
return l;
}
ByteVector &strip(ByteVector &b) {
if (b.endsWith('\0'))
b.resize(b.size() - 1);
return b;
}
ByteVectorList &strip(ByteVectorList &l) {
for (ByteVectorList::Iterator it = l.begin(); it != l.end(); ++it) {
strip(*it);
}
return l;
}
} // namespace
////////////////////////////////////////////////////////////////////////////////
// public methods
////////////////////////////////////////////////////////////////////////////////
TableOfContentsFrame::TableOfContentsFrame(const ID3v2::Header *tagHeader, const ByteVector &data) :
ID3v2::Frame(data),
d(new TableOfContentsFramePrivate())
{
TableOfContentsFrame::TableOfContentsFrame(const ID3v2::Header *tagHeader, const ByteVector &data) : ID3v2::Frame(data),
d(new TableOfContentsFramePrivate()) {
d->tagHeader = tagHeader;
setData(data);
}
TableOfContentsFrame::TableOfContentsFrame(const ByteVector &elementID,
const ByteVectorList &children,
const FrameList &embeddedFrames) :
ID3v2::Frame("CTOC"),
d(new TableOfContentsFramePrivate())
{
const ByteVectorList &children,
const FrameList &embeddedFrames) : ID3v2::Frame("CTOC"),
d(new TableOfContentsFramePrivate()) {
d->elementID = elementID;
strip(d->elementID);
d->childElements = children;
for(FrameList::ConstIterator it = embeddedFrames.begin(); it != embeddedFrames.end(); ++it)
for (FrameList::ConstIterator it = embeddedFrames.begin(); it != embeddedFrames.end(); ++it)
addEmbeddedFrame(*it);
}
TableOfContentsFrame::~TableOfContentsFrame()
{
TableOfContentsFrame::~TableOfContentsFrame() {
delete d;
}
ByteVector TableOfContentsFrame::elementID() const
{
ByteVector TableOfContentsFrame::elementID() const {
return d->elementID;
}
bool TableOfContentsFrame::isTopLevel() const
{
bool TableOfContentsFrame::isTopLevel() const {
return d->isTopLevel;
}
bool TableOfContentsFrame::isOrdered() const
{
bool TableOfContentsFrame::isOrdered() const {
return d->isOrdered;
}
unsigned int TableOfContentsFrame::entryCount() const
{
unsigned int TableOfContentsFrame::entryCount() const {
return d->childElements.size();
}
ByteVectorList TableOfContentsFrame::childElements() const
{
ByteVectorList TableOfContentsFrame::childElements() const {
return d->childElements;
}
void TableOfContentsFrame::setElementID(const ByteVector &eID)
{
void TableOfContentsFrame::setElementID(const ByteVector &eID) {
d->elementID = eID;
strip(d->elementID);
}
void TableOfContentsFrame::setIsTopLevel(const bool &t)
{
void TableOfContentsFrame::setIsTopLevel(const bool &t) {
d->isTopLevel = t;
}
void TableOfContentsFrame::setIsOrdered(const bool &o)
{
void TableOfContentsFrame::setIsOrdered(const bool &o) {
d->isOrdered = o;
}
void TableOfContentsFrame::setChildElements(const ByteVectorList &l)
{
void TableOfContentsFrame::setChildElements(const ByteVectorList &l) {
d->childElements = l;
strip(d->childElements);
}
void TableOfContentsFrame::addChildElement(const ByteVector &cE)
{
void TableOfContentsFrame::addChildElement(const ByteVector &cE) {
d->childElements.append(cE);
strip(d->childElements);
}
void TableOfContentsFrame::removeChildElement(const ByteVector &cE)
{
void TableOfContentsFrame::removeChildElement(const ByteVector &cE) {
ByteVectorList::Iterator it = d->childElements.find(cE);
if(it == d->childElements.end())
if (it == d->childElements.end())
it = d->childElements.find(cE + ByteVector("\0"));
d->childElements.erase(it);
}
const FrameListMap &TableOfContentsFrame::embeddedFrameListMap() const
{
const FrameListMap &TableOfContentsFrame::embeddedFrameListMap() const {
return d->embeddedFrameListMap;
}
const FrameList &TableOfContentsFrame::embeddedFrameList() const
{
const FrameList &TableOfContentsFrame::embeddedFrameList() const {
return d->embeddedFrameList;
}
const FrameList &TableOfContentsFrame::embeddedFrameList(const ByteVector &frameID) const
{
const FrameList &TableOfContentsFrame::embeddedFrameList(const ByteVector &frameID) const {
return d->embeddedFrameListMap[frameID];
}
void TableOfContentsFrame::addEmbeddedFrame(Frame *frame)
{
void TableOfContentsFrame::addEmbeddedFrame(Frame *frame) {
d->embeddedFrameList.append(frame);
d->embeddedFrameListMap[frame->frameID()].append(frame);
}
void TableOfContentsFrame::removeEmbeddedFrame(Frame *frame, bool del)
{
void TableOfContentsFrame::removeEmbeddedFrame(Frame *frame, bool del) {
// remove the frame from the frame list
FrameList::Iterator it = d->embeddedFrameList.find(frame);
d->embeddedFrameList.erase(it);
@@ -203,31 +176,30 @@ void TableOfContentsFrame::removeEmbeddedFrame(Frame *frame, bool del)
d->embeddedFrameListMap[frame->frameID()].erase(it);
// ...and delete as desired
if(del)
if (del)
delete frame;
}
void TableOfContentsFrame::removeEmbeddedFrames(const ByteVector &id)
{
void TableOfContentsFrame::removeEmbeddedFrames(const ByteVector &id) {
FrameList l = d->embeddedFrameListMap[id];
for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
for (FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
removeEmbeddedFrame(*it, true);
}
String TableOfContentsFrame::toString() const
{
String TableOfContentsFrame::toString() const {
String s = String(d->elementID) +
": top level: " + (d->isTopLevel ? "true" : "false") +
", ordered: " + (d->isOrdered ? "true" : "false");
": top level: " + (d->isTopLevel ? "true" : "false") +
", ordered: " + (d->isOrdered ? "true" : "false");
if(!d->childElements.isEmpty()) {
s+= ", chapters: [ " + String(d->childElements.toByteVector(", ")) + " ]";
if (!d->childElements.isEmpty()) {
s += ", chapters: [ " + String(d->childElements.toByteVector(", ")) + " ]";
}
if(!d->embeddedFrameList.isEmpty()) {
if (!d->embeddedFrameList.isEmpty()) {
StringList frameIDs;
for(FrameList::ConstIterator it = d->embeddedFrameList.begin();
it != d->embeddedFrameList.end(); ++it)
for (FrameList::ConstIterator it = d->embeddedFrameList.begin();
it != d->embeddedFrameList.end();
++it)
frameIDs.append((*it)->frameID());
s += ", sub-frames: [ " + frameIDs.toString(", ") + " ]";
}
@@ -235,8 +207,7 @@ String TableOfContentsFrame::toString() const
return s;
}
PropertyMap TableOfContentsFrame::asProperties() const
{
PropertyMap TableOfContentsFrame::asProperties() const {
PropertyMap map;
map.unsupportedData().append(frameID() + String("/") + d->elementID);
@@ -245,42 +216,39 @@ PropertyMap TableOfContentsFrame::asProperties() const
}
TableOfContentsFrame *TableOfContentsFrame::findByElementID(const ID3v2::Tag *tag,
const ByteVector &eID) // static
const ByteVector &eID) // static
{
ID3v2::FrameList tablesOfContents = tag->frameList("CTOC");
for(ID3v2::FrameList::ConstIterator it = tablesOfContents.begin();
it != tablesOfContents.end();
++it)
{
for (ID3v2::FrameList::ConstIterator it = tablesOfContents.begin();
it != tablesOfContents.end();
++it) {
TableOfContentsFrame *frame = dynamic_cast<TableOfContentsFrame *>(*it);
if(frame && frame->elementID() == eID)
if (frame && frame->elementID() == eID)
return frame;
}
return nullptr;
}
TableOfContentsFrame *TableOfContentsFrame::findTopLevel(const ID3v2::Tag *tag) // static
TableOfContentsFrame *TableOfContentsFrame::findTopLevel(const ID3v2::Tag *tag) // static
{
ID3v2::FrameList tablesOfContents = tag->frameList("CTOC");
for(ID3v2::FrameList::ConstIterator it = tablesOfContents.begin();
it != tablesOfContents.end();
++it)
{
for (ID3v2::FrameList::ConstIterator it = tablesOfContents.begin();
it != tablesOfContents.end();
++it) {
TableOfContentsFrame *frame = dynamic_cast<TableOfContentsFrame *>(*it);
if(frame && frame->isTopLevel() == true)
if (frame && frame->isTopLevel() == true)
return frame;
}
return nullptr;
}
void TableOfContentsFrame::parseFields(const ByteVector &data)
{
void TableOfContentsFrame::parseFields(const ByteVector &data) {
unsigned int size = data.size();
if(size < 6) {
if (size < 6) {
debug("A CTOC frame must contain at least 6 bytes (1 byte element ID terminated by "
"null, 1 byte flags, 1 byte entry count and 1 byte child element ID terminated "
"by null.");
@@ -293,24 +261,24 @@ void TableOfContentsFrame::parseFields(const ByteVector &data)
d->isTopLevel = (data.at(pos) & 2) != 0;
d->isOrdered = (data.at(pos++) & 1) != 0;
unsigned int entryCount = static_cast<unsigned char>(data.at(pos++));
for(unsigned int i = 0; i < entryCount; i++) {
for (unsigned int i = 0; i < entryCount; i++) {
ByteVector childElementID = readStringField(data, String::Latin1, &pos).data(String::Latin1);
d->childElements.append(childElementID);
}
size -= pos;
if(size < header()->size())
if (size < header()->size())
return;
while(embPos < size - header()->size()) {
while (embPos < size - header()->size()) {
Frame *frame = FrameFactory::instance()->createFrame(data.mid(pos + embPos), d->tagHeader);
if(!frame)
if (!frame)
return;
// Checks to make sure that frame parsed correctly.
if(frame->size() <= 0) {
if (frame->size() <= 0) {
delete frame;
return;
}
@@ -320,16 +288,15 @@ void TableOfContentsFrame::parseFields(const ByteVector &data)
}
}
ByteVector TableOfContentsFrame::renderFields() const
{
ByteVector TableOfContentsFrame::renderFields() const {
ByteVector data;
data.append(d->elementID);
data.append('\0');
char flags = 0;
if(d->isTopLevel)
if (d->isTopLevel)
flags += 2;
if(d->isOrdered)
if (d->isOrdered)
flags += 1;
data.append(flags);
data.append((char)(entryCount()));
@@ -347,10 +314,8 @@ ByteVector TableOfContentsFrame::renderFields() const
}
TableOfContentsFrame::TableOfContentsFrame(const ID3v2::Header *tagHeader,
const ByteVector &data, Header *h) :
Frame(h),
d(new TableOfContentsFramePrivate())
{
const ByteVector &data, Header *h) : Frame(h),
d(new TableOfContentsFramePrivate()) {
d->tagHeader = tagHeader;
parseFields(fieldData(data));
}

View File

@@ -34,125 +34,124 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
namespace ID3v2 {
/*!
/*!
* This is an implementation of ID3v2 table of contents frames. Purpose
* of this frame is to allow a table of contents to be defined.
*/
//! An implementation of ID3v2 table of contents frames
//! An implementation of ID3v2 table of contents frames
class TAGLIB_EXPORT TableOfContentsFrame : public ID3v2::Frame
{
friend class FrameFactory;
class TAGLIB_EXPORT TableOfContentsFrame : public ID3v2::Frame {
friend class FrameFactory;
public:
/*!
public:
/*!
* Creates a table of contents frame based on \a data. \a tagHeader is
* required as the internal frames are parsed based on the tag version.
*/
TableOfContentsFrame(const ID3v2::Header *tagHeader, const ByteVector &data);
TableOfContentsFrame(const ID3v2::Header *tagHeader, const ByteVector &data);
/*!
/*!
* Creates a table of contents frame with the element ID \a elementID,
* the child elements \a children and embedded frames, which become owned
* by this frame, in \a embeddedFrames.
*/
TableOfContentsFrame(const ByteVector &elementID,
const ByteVectorList &children = ByteVectorList(),
const FrameList &embeddedFrames = FrameList());
TableOfContentsFrame(const ByteVector &elementID,
const ByteVectorList &children = ByteVectorList(),
const FrameList &embeddedFrames = FrameList());
/*!
/*!
* Destroys the frame.
*/
~TableOfContentsFrame();
~TableOfContentsFrame();
/*!
/*!
* Returns the elementID of the frame. Element ID
* is a null terminated string, however it's not human-readable.
*
* \see setElementID()
*/
ByteVector elementID() const;
ByteVector elementID() const;
/*!
/*!
* Returns true, if the frame is top-level (doesn't have
* any parent CTOC frame).
*
* \see setIsTopLevel()
*/
bool isTopLevel() const;
bool isTopLevel() const;
/*!
/*!
* Returns true, if the child elements list entries
* are ordered.
*
* \see setIsOrdered()
*/
bool isOrdered() const;
bool isOrdered() const;
/*!
/*!
* Returns count of child elements of the frame. It always
* corresponds to size of child elements list.
*
* \see childElements()
*/
unsigned int entryCount() const;
unsigned int entryCount() const;
/*!
/*!
* Returns list of child elements of the frame.
*
* \see setChildElements()
*/
ByteVectorList childElements() const;
ByteVectorList childElements() const;
/*!
/*!
* Sets the elementID of the frame to \a eID. If \a eID isn't
* null terminated, a null char is appended automatically.
*
* \see elementID()
*/
void setElementID(const ByteVector &eID);
void setElementID(const ByteVector &eID);
/*!
/*!
* Sets, if the frame is top-level (doesn't have
* any parent CTOC frame).
*
* \see isTopLevel()
*/
void setIsTopLevel(const bool &t);
void setIsTopLevel(const bool &t);
/*!
/*!
* Sets, if the child elements list entries
* are ordered.
*
* \see isOrdered()
*/
void setIsOrdered(const bool &o);
void setIsOrdered(const bool &o);
/*!
/*!
* Sets list of child elements of the frame to \a l.
*
* \see childElements()
*/
void setChildElements(const ByteVectorList &l);
void setChildElements(const ByteVectorList &l);
/*!
/*!
* Adds \a cE to list of child elements of the frame.
*
* \see childElements()
*/
void addChildElement(const ByteVector &cE);
void addChildElement(const ByteVector &cE);
/*!
/*!
* Removes \a cE to list of child elements of the frame.
*
* \see childElements()
*/
void removeChildElement(const ByteVector &cE);
void removeChildElement(const ByteVector &cE);
/*!
/*!
* Returns a reference to the frame list map. This is an FrameListMap of
* all of the frames embedded in the CTOC frame.
*
@@ -166,9 +165,9 @@ namespace TagLib {
*
* \see embeddedFrameList()
*/
const FrameListMap &embeddedFrameListMap() const;
const FrameListMap &embeddedFrameListMap() const;
/*!
/*!
* Returns a reference to the embedded frame list. This is an FrameList
* of all of the frames embedded in the CTOC frame in the order that they
* were parsed.
@@ -179,9 +178,9 @@ namespace TagLib {
* \warning You should not modify this data structure directly, instead
* use addEmbeddedFrame() and removeEmbeddedFrame().
*/
const FrameList &embeddedFrameList() const;
const FrameList &embeddedFrameList() const;
/*!
/*!
* Returns the embedded frame list for frames with the id \a frameID
* or an empty list if there are no embedded frames of that type. This
* is just a convenience and is equivalent to:
@@ -192,71 +191,71 @@ namespace TagLib {
*
* \see embeddedFrameListMap()
*/
const FrameList &embeddedFrameList(const ByteVector &frameID) const;
const FrameList &embeddedFrameList(const ByteVector &frameID) const;
/*!
/*!
* Add an embedded frame to the CTOC frame. At this point the CTOC frame
* takes ownership of the embedded frame and will handle freeing its memory.
*
* \note Using this method will invalidate any pointers on the list
* returned by embeddedFrameList()
*/
void addEmbeddedFrame(Frame *frame);
void addEmbeddedFrame(Frame *frame);
/*!
/*!
* Remove an embedded frame from the CTOC frame. If \a del is true the frame's
* memory will be freed; if it is false, it must be deleted by the user.
*
* \note Using this method will invalidate any pointers on the list
* returned by embeddedFrameList()
*/
void removeEmbeddedFrame(Frame *frame, bool del = true);
void removeEmbeddedFrame(Frame *frame, bool del = true);
/*!
/*!
* Remove all embedded frames of type \a id from the CTOC frame and free their
* memory.
*
* \note Using this method will invalidate any pointers on the list
* returned by embeddedFrameList()
*/
void removeEmbeddedFrames(const ByteVector &id);
void removeEmbeddedFrames(const ByteVector &id);
virtual String toString() const;
virtual String toString() const;
PropertyMap asProperties() const;
PropertyMap asProperties() const;
/*!
/*!
* CTOC frames each have a unique element ID. This searches for a CTOC
* frame with the element ID \a eID and returns a pointer to it. This
* can be used to link together parent and child CTOC frames.
*
* \see elementID()
*/
static TableOfContentsFrame *findByElementID(const Tag *tag, const ByteVector &eID);
static TableOfContentsFrame *findByElementID(const Tag *tag, const ByteVector &eID);
/*!
/*!
* CTOC frames each contain a flag that indicates, if CTOC frame is top-level (there isn't
* any frame, which contains this frame in its child elements list). Only a single frame
* within tag can be top-level. This searches for a top-level CTOC frame.
*
* \see isTopLevel()
*/
static TableOfContentsFrame *findTopLevel(const Tag *tag);
static TableOfContentsFrame *findTopLevel(const Tag *tag);
protected:
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
protected:
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
private:
TableOfContentsFrame(const ID3v2::Header *tagHeader, const ByteVector &data, Header *h);
TableOfContentsFrame(const TableOfContentsFrame &);
TableOfContentsFrame &operator=(const TableOfContentsFrame &);
private:
TableOfContentsFrame(const ID3v2::Header *tagHeader, const ByteVector &data, Header *h);
TableOfContentsFrame(const TableOfContentsFrame &);
TableOfContentsFrame &operator=(const TableOfContentsFrame &);
class TableOfContentsFramePrivate;
TableOfContentsFramePrivate *d;
};
}
}
}
class TableOfContentsFramePrivate;
TableOfContentsFramePrivate *d;
};
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -32,9 +32,8 @@
using namespace Strawberry_TagLib::TagLib;
using namespace ID3v2;
class TextIdentificationFrame::TextIdentificationFramePrivate
{
public:
class TextIdentificationFrame::TextIdentificationFramePrivate {
public:
TextIdentificationFramePrivate() : textEncoding(String::Latin1) {}
String::Type textEncoding;
StringList fieldList;
@@ -44,38 +43,34 @@ public:
// TextIdentificationFrame public members
////////////////////////////////////////////////////////////////////////////////
TextIdentificationFrame::TextIdentificationFrame(const ByteVector &type, String::Type encoding) :
Frame(type),
d(new TextIdentificationFramePrivate())
{
TextIdentificationFrame::TextIdentificationFrame(const ByteVector &type, String::Type encoding) : Frame(type),
d(new TextIdentificationFramePrivate()) {
d->textEncoding = encoding;
}
TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data) :
Frame(data),
d(new TextIdentificationFramePrivate())
{
TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data) : Frame(data),
d(new TextIdentificationFramePrivate()) {
setData(data);
}
TextIdentificationFrame *TextIdentificationFrame::createTIPLFrame(const PropertyMap &properties) // static
TextIdentificationFrame *TextIdentificationFrame::createTIPLFrame(const PropertyMap &properties) // static
{
TextIdentificationFrame *frame = new TextIdentificationFrame("TIPL");
StringList l;
for(PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it){
for (PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it) {
l.append(it->first);
l.append(it->second.toString(",")); // comma-separated list of names
l.append(it->second.toString(",")); // comma-separated list of names
}
frame->setText(l);
return frame;
}
TextIdentificationFrame *TextIdentificationFrame::createTMCLFrame(const PropertyMap &properties) // static
TextIdentificationFrame *TextIdentificationFrame::createTMCLFrame(const PropertyMap &properties) // static
{
TextIdentificationFrame *frame = new TextIdentificationFrame("TMCL");
StringList l;
for(PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it){
if(!it->first.startsWith(instrumentPrefix)) // should not happen
for (PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it) {
if (!it->first.startsWith(instrumentPrefix)) // should not happen
continue;
l.append(it->first.substr(instrumentPrefix.size()));
l.append(it->second.toString(","));
@@ -84,92 +79,84 @@ TextIdentificationFrame *TextIdentificationFrame::createTMCLFrame(const Property
return frame;
}
TextIdentificationFrame::~TextIdentificationFrame()
{
TextIdentificationFrame::~TextIdentificationFrame() {
delete d;
}
void TextIdentificationFrame::setText(const StringList &l)
{
void TextIdentificationFrame::setText(const StringList &l) {
d->fieldList = l;
}
void TextIdentificationFrame::setText(const String &s)
{
void TextIdentificationFrame::setText(const String &s) {
d->fieldList = s;
}
String TextIdentificationFrame::toString() const
{
String TextIdentificationFrame::toString() const {
return d->fieldList.toString();
}
StringList TextIdentificationFrame::fieldList() const
{
StringList TextIdentificationFrame::fieldList() const {
return d->fieldList;
}
String::Type TextIdentificationFrame::textEncoding() const
{
String::Type TextIdentificationFrame::textEncoding() const {
return d->textEncoding;
}
void TextIdentificationFrame::setTextEncoding(String::Type encoding)
{
void TextIdentificationFrame::setTextEncoding(String::Type encoding) {
d->textEncoding = encoding;
}
namespace
{
// array of allowed TIPL prefixes and their corresponding key value
const char* involvedPeople[][2] = {
{"ARRANGER", "ARRANGER"},
{"ENGINEER", "ENGINEER"},
{"PRODUCER", "PRODUCER"},
{"DJ-MIX", "DJMIXER"},
{"MIX", "MIXER"},
};
const size_t involvedPeopleSize = sizeof(involvedPeople) / sizeof(involvedPeople[0]);
}
namespace {
// array of allowed TIPL prefixes and their corresponding key value
const char *involvedPeople[][2] = {
{ "ARRANGER", "ARRANGER" },
{ "ENGINEER", "ENGINEER" },
{ "PRODUCER", "PRODUCER" },
{ "DJ-MIX", "DJMIXER" },
{ "MIX", "MIXER" },
};
const size_t involvedPeopleSize = sizeof(involvedPeople) / sizeof(involvedPeople[0]);
} // namespace
const KeyConversionMap &TextIdentificationFrame::involvedPeopleMap() // static
const KeyConversionMap &TextIdentificationFrame::involvedPeopleMap() // static
{
static KeyConversionMap m;
if(m.isEmpty()) {
for(size_t i = 0; i < involvedPeopleSize; ++i)
if (m.isEmpty()) {
for (size_t i = 0; i < involvedPeopleSize; ++i)
m.insert(involvedPeople[i][1], involvedPeople[i][0]);
}
return m;
}
PropertyMap TextIdentificationFrame::asProperties() const
{
if(frameID() == "TIPL")
PropertyMap TextIdentificationFrame::asProperties() const {
if (frameID() == "TIPL")
return makeTIPLProperties();
if(frameID() == "TMCL")
if (frameID() == "TMCL")
return makeTMCLProperties();
PropertyMap map;
String tagName = frameIDToKey(frameID());
if(tagName.isEmpty()) {
if (tagName.isEmpty()) {
map.unsupportedData().append(frameID());
return map;
}
StringList values = fieldList();
if(tagName == "GENRE") {
if (tagName == "GENRE") {
// Special case: Support ID3v1-style genre numbers. They are not officially supported in
// ID3v2, however it seems that still a lot of programs use them.
for(StringList::Iterator it = values.begin(); it != values.end(); ++it) {
for (StringList::Iterator it = values.begin(); it != values.end(); ++it) {
bool ok = false;
int test = it->toInt(&ok); // test if the genre value is an integer
if(ok)
int test = it->toInt(&ok); // test if the genre value is an integer
if (ok)
*it = ID3v1::genre(test);
}
} else if(tagName == "DATE") {
for(StringList::Iterator it = values.begin(); it != values.end(); ++it) {
}
else if (tagName == "DATE") {
for (StringList::Iterator it = values.begin(); it != values.end(); ++it) {
// ID3v2 specifies ISO8601 timestamps which contain a 'T' as separator between date and time.
// Since this is unusual in other formats, the T is removed.
int tpos = it->find("T");
if(tpos != -1)
if (tpos != -1)
(*it)[tpos] = ' ';
}
}
@@ -182,11 +169,10 @@ PropertyMap TextIdentificationFrame::asProperties() const
// TextIdentificationFrame protected members
////////////////////////////////////////////////////////////////////////////////
void TextIdentificationFrame::parseFields(const ByteVector &data)
{
void TextIdentificationFrame::parseFields(const ByteVector &data) {
// Don't try to parse invalid frames
if(data.size() < 2)
if (data.size() < 2)
return;
// read the string data type (the first byte of the field data)
@@ -202,10 +188,10 @@ void TextIdentificationFrame::parseFields(const ByteVector &data)
int dataLength = data.size() - 1;
while(dataLength > 0 && data[dataLength] == 0)
while (dataLength > 0 && data[dataLength] == 0)
dataLength--;
while(dataLength % byteAlign != 0)
while (dataLength % byteAlign != 0)
dataLength++;
ByteVectorList l = ByteVectorList::split(data.mid(1, dataLength), textDelimiter(d->textEncoding), byteAlign);
@@ -215,9 +201,9 @@ void TextIdentificationFrame::parseFields(const ByteVector &data)
// append those split values to the list and make sure that the new string's
// type is the same specified for this frame
for(ByteVectorList::ConstIterator it = l.begin(); it != l.end(); it++) {
if(!(*it).isEmpty()) {
if(d->textEncoding == String::Latin1)
for (ByteVectorList::ConstIterator it = l.begin(); it != l.end(); it++) {
if (!(*it).isEmpty()) {
if (d->textEncoding == String::Latin1)
d->fieldList.append(Tag::latin1StringHandler()->parse(*it));
else
d->fieldList.append(String(*it, d->textEncoding));
@@ -225,21 +211,20 @@ void TextIdentificationFrame::parseFields(const ByteVector &data)
}
}
ByteVector TextIdentificationFrame::renderFields() const
{
ByteVector TextIdentificationFrame::renderFields() const {
String::Type encoding = checkTextEncoding(d->fieldList, d->textEncoding);
ByteVector v;
v.append(char(encoding));
for(StringList::ConstIterator it = d->fieldList.begin(); it != d->fieldList.end(); it++) {
for (StringList::ConstIterator it = d->fieldList.begin(); it != d->fieldList.end(); it++) {
// Since the field list is null delimited, if this is not the first
// element in the list, append the appropriate delimiter for this
// encoding.
if(it != d->fieldList.begin())
if (it != d->fieldList.begin())
v.append(textDelimiter(encoding));
v.append((*it).data(encoding));
@@ -252,31 +237,28 @@ ByteVector TextIdentificationFrame::renderFields() const
// TextIdentificationFrame private members
////////////////////////////////////////////////////////////////////////////////
TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new TextIdentificationFramePrivate())
{
TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data, Header *h) : Frame(h),
d(new TextIdentificationFramePrivate()) {
parseFields(fieldData(data));
}
PropertyMap TextIdentificationFrame::makeTIPLProperties() const
{
PropertyMap TextIdentificationFrame::makeTIPLProperties() const {
PropertyMap map;
if(fieldList().size() % 2 != 0){
if (fieldList().size() % 2 != 0) {
// according to the ID3 spec, TIPL must contain an even number of entries
map.unsupportedData().append(frameID());
return map;
}
StringList l = fieldList();
for(StringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
for (StringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
bool found = false;
for(size_t i = 0; i < involvedPeopleSize; ++i)
if(*it == involvedPeople[i][0]) {
for (size_t i = 0; i < involvedPeopleSize; ++i)
if (*it == involvedPeople[i][0]) {
map.insert(involvedPeople[i][1], (++it)->split(","));
found = true;
break;
}
if(!found){
if (!found) {
// invalid involved role -> mark whole frame as unsupported in order to be consistent with writing
map.clear();
map.unsupportedData().append(frameID());
@@ -286,18 +268,17 @@ PropertyMap TextIdentificationFrame::makeTIPLProperties() const
return map;
}
PropertyMap TextIdentificationFrame::makeTMCLProperties() const
{
PropertyMap TextIdentificationFrame::makeTMCLProperties() const {
PropertyMap map;
if(fieldList().size() % 2 != 0){
if (fieldList().size() % 2 != 0) {
// according to the ID3 spec, TMCL must contain an even number of entries
map.unsupportedData().append(frameID());
return map;
}
StringList l = fieldList();
for(StringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
for (StringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
String instrument = it->upper();
if(instrument.isEmpty()) {
if (instrument.isEmpty()) {
// instrument is not a valid key -> frame unsupported
map.clear();
map.unsupportedData().append(frameID());
@@ -312,10 +293,8 @@ PropertyMap TextIdentificationFrame::makeTMCLProperties() const
// UserTextIdentificationFrame public members
////////////////////////////////////////////////////////////////////////////////
UserTextIdentificationFrame::UserTextIdentificationFrame(String::Type encoding) :
TextIdentificationFrame("TXXX", encoding),
d(0)
{
UserTextIdentificationFrame::UserTextIdentificationFrame(String::Type encoding) : TextIdentificationFrame("TXXX", encoding),
d(0) {
StringList l;
l.append(String());
l.append(String());
@@ -323,66 +302,54 @@ UserTextIdentificationFrame::UserTextIdentificationFrame(String::Type encoding)
}
UserTextIdentificationFrame::UserTextIdentificationFrame(const ByteVector &data) :
TextIdentificationFrame(data)
{
UserTextIdentificationFrame::UserTextIdentificationFrame(const ByteVector &data) : TextIdentificationFrame(data) {
checkFields();
}
UserTextIdentificationFrame::UserTextIdentificationFrame(const String &description, const StringList &values, String::Type encoding) :
TextIdentificationFrame("TXXX", encoding),
d(0)
{
UserTextIdentificationFrame::UserTextIdentificationFrame(const String &description, const StringList &values, String::Type encoding) : TextIdentificationFrame("TXXX", encoding),
d(0) {
setDescription(description);
setText(values);
}
String UserTextIdentificationFrame::toString() const
{
String UserTextIdentificationFrame::toString() const {
// first entry is the description itself, drop from values list
StringList l = fieldList();
for(StringList::Iterator it = l.begin(); it != l.end(); ++it) {
for (StringList::Iterator it = l.begin(); it != l.end(); ++it) {
l.erase(it);
break;
}
return "[" + description() + "] " + l.toString();
}
String UserTextIdentificationFrame::description() const
{
return !TextIdentificationFrame::fieldList().isEmpty()
? TextIdentificationFrame::fieldList().front()
: String();
String UserTextIdentificationFrame::description() const {
return !TextIdentificationFrame::fieldList().isEmpty() ? TextIdentificationFrame::fieldList().front() : String();
}
StringList UserTextIdentificationFrame::fieldList() const
{
StringList UserTextIdentificationFrame::fieldList() const {
// TODO: remove this function
return TextIdentificationFrame::fieldList();
}
void UserTextIdentificationFrame::setText(const String &text)
{
if(description().isEmpty())
void UserTextIdentificationFrame::setText(const String &text) {
if (description().isEmpty())
setDescription(String());
TextIdentificationFrame::setText(StringList(description()).append(text));
}
void UserTextIdentificationFrame::setText(const StringList &fields)
{
if(description().isEmpty())
void UserTextIdentificationFrame::setText(const StringList &fields) {
if (description().isEmpty())
setDescription(String());
TextIdentificationFrame::setText(StringList(description()).append(fields));
}
void UserTextIdentificationFrame::setDescription(const String &s)
{
void UserTextIdentificationFrame::setDescription(const String &s) {
StringList l = fieldList();
if(l.isEmpty())
if (l.isEmpty())
l.append(s);
else
l[0] = s;
@@ -390,24 +357,23 @@ void UserTextIdentificationFrame::setDescription(const String &s)
TextIdentificationFrame::setText(l);
}
PropertyMap UserTextIdentificationFrame::asProperties() const
{
PropertyMap UserTextIdentificationFrame::asProperties() const {
PropertyMap map;
String tagName = txxxToKey(description());
StringList v = fieldList();
for(StringList::ConstIterator it = v.begin(); it != v.end(); ++it)
if(it != v.begin())
for (StringList::ConstIterator it = v.begin(); it != v.end(); ++it)
if (it != v.begin())
map.insert(tagName, *it);
return map;
}
UserTextIdentificationFrame *UserTextIdentificationFrame::find(
ID3v2::Tag *tag, const String &description) // static
ID3v2::Tag *tag, const String &description) // static
{
FrameList l = tag->frameList("TXXX");
for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it) {
for (FrameList::ConstIterator it = l.begin(); it != l.end(); ++it) {
UserTextIdentificationFrame *f = dynamic_cast<UserTextIdentificationFrame *>(*it);
if(f && f->description() == description)
if (f && f->description() == description)
return f;
}
return nullptr;
@@ -417,18 +383,15 @@ UserTextIdentificationFrame *UserTextIdentificationFrame::find(
// UserTextIdentificationFrame private members
////////////////////////////////////////////////////////////////////////////////
UserTextIdentificationFrame::UserTextIdentificationFrame(const ByteVector &data, Header *h) :
TextIdentificationFrame(data, h)
{
UserTextIdentificationFrame::UserTextIdentificationFrame(const ByteVector &data, Header *h) : TextIdentificationFrame(data, h) {
checkFields();
}
void UserTextIdentificationFrame::checkFields()
{
void UserTextIdentificationFrame::checkFields() {
int fields = fieldList().size();
if(fields == 0)
if (fields == 0)
setDescription(String());
if(fields <= 1)
if (fields <= 1)
setText(String());
}

View File

@@ -35,14 +35,14 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
namespace ID3v2 {
class Tag;
typedef Map<String, String> KeyConversionMap;
class Tag;
typedef Map<String, String> KeyConversionMap;
//! An ID3v2 text identification frame implementation
//! An ID3v2 text identification frame implementation
/*!
/*!
* This is an implementation of the most common type of ID3v2 frame -- text
* identification frames. There are a number of variations on this. Those
* enumerated in the ID3v2.4 standard are:
@@ -104,12 +104,11 @@ namespace TagLib {
* (with the encoding flag appropriately set in the output).
*/
class TAGLIB_EXPORT TextIdentificationFrame : public Frame
{
friend class FrameFactory;
class TAGLIB_EXPORT TextIdentificationFrame : public Frame {
friend class FrameFactory;
public:
/*!
public:
/*!
* Construct an empty frame of type \a type. Uses \a encoding as the
* default text encoding.
*
@@ -118,34 +117,34 @@ namespace TagLib {
*
* \note Please see the note in the class description regarding Latin1.
*/
TextIdentificationFrame(const ByteVector &type, String::Type encoding);
TextIdentificationFrame(const ByteVector &type, String::Type encoding);
/*!
/*!
* This is a dual purpose constructor. \a data can either be binary data
* that should be parsed or (at a minimum) the frame ID.
*/
explicit TextIdentificationFrame(const ByteVector &data);
explicit TextIdentificationFrame(const ByteVector &data);
/*!
/*!
* This is a special factory method to create a TIPL (involved people list)
* frame from the given \a properties. Will parse key=[list of values] data
* into the TIPL format as specified in the ID3 standard.
*/
static TextIdentificationFrame *createTIPLFrame(const PropertyMap &properties);
static TextIdentificationFrame *createTIPLFrame(const PropertyMap &properties);
/*!
/*!
* This is a special factory method to create a TMCL (musician credits list)
* frame from the given \a properties. Will parse key=[list of values] data
* into the TMCL format as specified in the ID3 standard, where key should be
* of the form instrumentPrefix:instrument.
*/
static TextIdentificationFrame *createTMCLFrame(const PropertyMap &properties);
/*!
static TextIdentificationFrame *createTMCLFrame(const PropertyMap &properties);
/*!
* Destroys this TextIdentificationFrame instance.
*/
virtual ~TextIdentificationFrame();
virtual ~TextIdentificationFrame();
/*!
/*!
* Text identification frames are a list of string fields.
*
* This function will accept either a StringList or a String (using the
@@ -155,14 +154,14 @@ namespace TagLib {
* strings passed in are not of the same encoding. Please use
* setEncoding(s.type()) if you wish to change the encoding of the frame.
*/
void setText(const StringList &l);
void setText(const StringList &l);
// Reimplementations.
// Reimplementations.
virtual void setText(const String &s);
virtual String toString() const;
virtual void setText(const String &s);
virtual String toString() const;
/*!
/*!
* Returns the text encoding that will be used in rendering this frame.
* This defaults to the type that was either specified in the constructor
* or read from the frame when parsed.
@@ -172,9 +171,9 @@ namespace TagLib {
* \see setTextEncoding()
* \see render()
*/
String::Type textEncoding() const;
String::Type textEncoding() const;
/*!
/*!
* Sets the text encoding to be used when rendering this frame to
* \a encoding.
*
@@ -183,51 +182,51 @@ namespace TagLib {
* \see textEncoding()
* \see render()
*/
void setTextEncoding(String::Type encoding);
void setTextEncoding(String::Type encoding);
/*!
/*!
* Returns a list of the strings in this frame.
*/
StringList fieldList() const;
StringList fieldList() const;
/*!
/*!
* Returns a KeyConversionMap mapping a role as it would be used in a PropertyMap
* to the corresponding key used in a TIPL ID3 frame to describe that role.
*/
static const KeyConversionMap &involvedPeopleMap();
static const KeyConversionMap &involvedPeopleMap();
PropertyMap asProperties() const;
PropertyMap asProperties() const;
protected:
// Reimplementations.
protected:
// Reimplementations.
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
/*!
/*!
* The constructor used by the FrameFactory.
*/
TextIdentificationFrame(const ByteVector &data, Header *h);
TextIdentificationFrame(const ByteVector &data, Header *h);
private:
TextIdentificationFrame(const TextIdentificationFrame &);
TextIdentificationFrame &operator=(const TextIdentificationFrame &);
private:
TextIdentificationFrame(const TextIdentificationFrame &);
TextIdentificationFrame &operator=(const TextIdentificationFrame &);
/*!
/*!
* Parses the special structure of a TIPL frame
* Only the whitelisted roles "ARRANGER", "ENGINEER", "PRODUCER",
* "DJMIXER" (ID3: "DJ-MIX") and "MIXER" (ID3: "MIX") are allowed.
*/
PropertyMap makeTIPLProperties() const;
/*!
PropertyMap makeTIPLProperties() const;
/*!
* Parses the special structure of a TMCL frame.
*/
PropertyMap makeTMCLProperties() const;
class TextIdentificationFramePrivate;
TextIdentificationFramePrivate *d;
};
PropertyMap makeTMCLProperties() const;
class TextIdentificationFramePrivate;
TextIdentificationFramePrivate *d;
};
/*!
/*!
* This is a specialization of text identification frames that allows for
* user defined entries. Each entry has a description in addition to the
* normal list of fields that a text identification frame has.
@@ -235,49 +234,48 @@ namespace TagLib {
* This description identifies the frame and must be unique.
*/
//! An ID3v2 custom text identification frame implementation
//! An ID3v2 custom text identification frame implementation
class TAGLIB_EXPORT UserTextIdentificationFrame : public TextIdentificationFrame
{
friend class FrameFactory;
class TAGLIB_EXPORT UserTextIdentificationFrame : public TextIdentificationFrame {
friend class FrameFactory;
public:
/*!
public:
/*!
* Constructs an empty user defined text identification frame. For this to be
* a useful frame both a description and text must be set.
*/
explicit UserTextIdentificationFrame(String::Type encoding = String::Latin1);
explicit UserTextIdentificationFrame(String::Type encoding = String::Latin1);
/*!
/*!
* Creates a frame based on \a data.
*/
explicit UserTextIdentificationFrame(const ByteVector &data);
explicit UserTextIdentificationFrame(const ByteVector &data);
/*!
/*!
* Creates a user defined text identification frame with the given \a description
* and \a values.
*/
UserTextIdentificationFrame(const String &description, const StringList &values, String::Type encoding = String::UTF8);
UserTextIdentificationFrame(const String &description, const StringList &values, String::Type encoding = String::UTF8);
virtual String toString() const;
virtual String toString() const;
/*!
/*!
* Returns the description for this frame.
*/
String description() const;
String description() const;
/*!
/*!
* Sets the description of the frame to \a s. \a s must be unique. You can
* check for the presence of another user defined text frame of the same type
* using find() and testing for null.
*/
void setDescription(const String &s);
void setDescription(const String &s);
StringList fieldList() const;
void setText(const String &text);
void setText(const StringList &fields);
StringList fieldList() const;
void setText(const String &text);
void setText(const StringList &fields);
/*!
/*!
* A UserTextIdentificationFrame is parsed into a PropertyMap as follows:
* - the key is the frame's description, uppercased
* - if the description contains '::', only the substring after that
@@ -290,26 +288,26 @@ namespace TagLib {
* in the value list, in order to be compatible with TagLib which copies
* the description() into the fieldList().
*/
PropertyMap asProperties() const;
PropertyMap asProperties() const;
/*!
/*!
* Searches for the user defined text frame with the description \a description
* in \a tag. This returns null if no matching frames were found.
*/
static UserTextIdentificationFrame *find(Tag *tag, const String &description);
static UserTextIdentificationFrame *find(Tag *tag, const String &description);
private:
UserTextIdentificationFrame(const ByteVector &data, Header *h);
UserTextIdentificationFrame(const TextIdentificationFrame &);
UserTextIdentificationFrame &operator=(const UserTextIdentificationFrame &);
private:
UserTextIdentificationFrame(const ByteVector &data, Header *h);
UserTextIdentificationFrame(const TextIdentificationFrame &);
UserTextIdentificationFrame &operator=(const UserTextIdentificationFrame &);
void checkFields();
void checkFields();
class UserTextIdentificationFramePrivate;
UserTextIdentificationFramePrivate *d;
};
class UserTextIdentificationFramePrivate;
UserTextIdentificationFramePrivate *d;
};
}
}
}
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -33,9 +33,8 @@
using namespace Strawberry_TagLib::TagLib;
using namespace ID3v2;
class UniqueFileIdentifierFrame::UniqueFileIdentifierFramePrivate
{
public:
class UniqueFileIdentifierFrame::UniqueFileIdentifierFramePrivate {
public:
String owner;
ByteVector identifier;
};
@@ -44,55 +43,44 @@ public:
// public methods
////////////////////////////////////////////////////////////////////////////////
UniqueFileIdentifierFrame::UniqueFileIdentifierFrame(const ByteVector &data) :
ID3v2::Frame(data),
d(new UniqueFileIdentifierFramePrivate())
{
UniqueFileIdentifierFrame::UniqueFileIdentifierFrame(const ByteVector &data) : ID3v2::Frame(data),
d(new UniqueFileIdentifierFramePrivate()) {
setData(data);
}
UniqueFileIdentifierFrame::UniqueFileIdentifierFrame(const String &owner, const ByteVector &id) :
ID3v2::Frame("UFID"),
d(new UniqueFileIdentifierFramePrivate())
{
UniqueFileIdentifierFrame::UniqueFileIdentifierFrame(const String &owner, const ByteVector &id) : ID3v2::Frame("UFID"),
d(new UniqueFileIdentifierFramePrivate()) {
d->owner = owner;
d->identifier = id;
}
UniqueFileIdentifierFrame::~UniqueFileIdentifierFrame()
{
UniqueFileIdentifierFrame::~UniqueFileIdentifierFrame() {
delete d;
}
String UniqueFileIdentifierFrame::owner() const
{
return d->owner;
String UniqueFileIdentifierFrame::owner() const {
return d->owner;
}
ByteVector UniqueFileIdentifierFrame::identifier() const
{
ByteVector UniqueFileIdentifierFrame::identifier() const {
return d->identifier;
}
void UniqueFileIdentifierFrame::setOwner(const String &s)
{
void UniqueFileIdentifierFrame::setOwner(const String &s) {
d->owner = s;
}
void UniqueFileIdentifierFrame::setIdentifier(const ByteVector &v)
{
void UniqueFileIdentifierFrame::setIdentifier(const ByteVector &v) {
d->identifier = v;
}
String UniqueFileIdentifierFrame::toString() const
{
String UniqueFileIdentifierFrame::toString() const {
return String();
}
PropertyMap UniqueFileIdentifierFrame::asProperties() const
{
PropertyMap UniqueFileIdentifierFrame::asProperties() const {
PropertyMap map;
if(d->owner == "http://musicbrainz.org") {
if (d->owner == "http://musicbrainz.org") {
map.insert("MUSICBRAINZ_TRACKID", String(d->identifier));
}
else {
@@ -101,25 +89,23 @@ PropertyMap UniqueFileIdentifierFrame::asProperties() const
return map;
}
UniqueFileIdentifierFrame *UniqueFileIdentifierFrame::findByOwner(const ID3v2::Tag *tag, const String &o) // static
UniqueFileIdentifierFrame *UniqueFileIdentifierFrame::findByOwner(const ID3v2::Tag *tag, const String &o) // static
{
ID3v2::FrameList comments = tag->frameList("UFID");
for(ID3v2::FrameList::ConstIterator it = comments.begin();
it != comments.end();
++it)
{
for (ID3v2::FrameList::ConstIterator it = comments.begin();
it != comments.end();
++it) {
UniqueFileIdentifierFrame *frame = dynamic_cast<UniqueFileIdentifierFrame *>(*it);
if(frame && frame->owner() == o)
if (frame && frame->owner() == o)
return frame;
}
return nullptr;
}
void UniqueFileIdentifierFrame::parseFields(const ByteVector &data)
{
if(data.size() < 1) {
void UniqueFileIdentifierFrame::parseFields(const ByteVector &data) {
if (data.size() < 1) {
debug("An UFID frame must contain at least 1 byte.");
return;
}
@@ -129,8 +115,7 @@ void UniqueFileIdentifierFrame::parseFields(const ByteVector &data)
d->identifier = data.mid(pos);
}
ByteVector UniqueFileIdentifierFrame::renderFields() const
{
ByteVector UniqueFileIdentifierFrame::renderFields() const {
ByteVector data;
data.append(d->owner.data(String::Latin1));
@@ -140,9 +125,7 @@ ByteVector UniqueFileIdentifierFrame::renderFields() const
return data;
}
UniqueFileIdentifierFrame::UniqueFileIdentifierFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new UniqueFileIdentifierFramePrivate())
{
UniqueFileIdentifierFrame::UniqueFileIdentifierFrame(const ByteVector &data, Header *h) : Frame(h),
d(new UniqueFileIdentifierFramePrivate()) {
parseFields(fieldData(data));
}

View File

@@ -31,38 +31,37 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
namespace ID3v2 {
/*!
/*!
* This is an implementation of ID3v2 unique file identifier frames. This
* frame is used to identify the file in an arbitrary database identified
* by the owner field.
*/
//! An implementation of ID3v2 unique identifier frames
//! An implementation of ID3v2 unique identifier frames
class TAGLIB_EXPORT UniqueFileIdentifierFrame : public ID3v2::Frame
{
friend class FrameFactory;
class TAGLIB_EXPORT UniqueFileIdentifierFrame : public ID3v2::Frame {
friend class FrameFactory;
public:
/*!
public:
/*!
* Creates a unique file identifier frame based on \a data.
*/
UniqueFileIdentifierFrame(const ByteVector &data);
UniqueFileIdentifierFrame(const ByteVector &data);
/*!
/*!
* Creates a unique file identifier frame with the owner \a owner and
* the identification \a id.
*/
UniqueFileIdentifierFrame(const String &owner, const ByteVector &id);
UniqueFileIdentifierFrame(const String &owner, const ByteVector &id);
/*!
/*!
* Destroys the frame.
*/
~UniqueFileIdentifierFrame();
~UniqueFileIdentifierFrame();
/*!
/*!
* Returns the owner for the frame; essentially this is the key for
* determining which identification scheme this key belongs to. This
* will usually either be an email address or URL for the person or tool
@@ -70,56 +69,56 @@ namespace TagLib {
*
* \see setOwner()
*/
String owner() const;
String owner() const;
/*!
/*!
* Returns the unique identifier. Though sometimes this is a text string
* it also may be binary data and as much should be assumed when handling
* it.
*/
ByteVector identifier() const;
ByteVector identifier() const;
/*!
/*!
* Sets the owner of the identification scheme to \a s.
*
* \see owner()
*/
void setOwner(const String &s);
void setOwner(const String &s);
/*!
/*!
* Sets the unique file identifier to \a v.
*
* \see identifier()
*/
void setIdentifier(const ByteVector &v);
void setIdentifier(const ByteVector &v);
virtual String toString() const;
virtual String toString() const;
PropertyMap asProperties() const;
PropertyMap asProperties() const;
/*!
/*!
* UFID frames each have a unique owner. This searches for a UFID
* frame with the owner \a o and returns a pointer to it.
*
* \see owner()
*/
static UniqueFileIdentifierFrame *findByOwner(const Tag *tag, const String &o);
static UniqueFileIdentifierFrame *findByOwner(const Tag *tag, const String &o);
protected:
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
protected:
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
private:
UniqueFileIdentifierFrame(const UniqueFileIdentifierFrame &);
UniqueFileIdentifierFrame &operator=(const UniqueFileIdentifierFrame &);
private:
UniqueFileIdentifierFrame(const UniqueFileIdentifierFrame &);
UniqueFileIdentifierFrame &operator=(const UniqueFileIdentifierFrame &);
UniqueFileIdentifierFrame(const ByteVector &data, Header *h);
UniqueFileIdentifierFrame(const ByteVector &data, Header *h);
class UniqueFileIdentifierFramePrivate;
UniqueFileIdentifierFramePrivate *d;
};
}
}
}
class UniqueFileIdentifierFramePrivate;
UniqueFileIdentifierFramePrivate *d;
};
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -28,9 +28,8 @@
using namespace Strawberry_TagLib::TagLib;
using namespace ID3v2;
class UnknownFrame::UnknownFramePrivate
{
public:
class UnknownFrame::UnknownFramePrivate {
public:
ByteVector fieldData;
};
@@ -38,25 +37,20 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
UnknownFrame::UnknownFrame(const ByteVector &data) :
Frame(data),
d(new UnknownFramePrivate())
{
UnknownFrame::UnknownFrame(const ByteVector &data) : Frame(data),
d(new UnknownFramePrivate()) {
setData(data);
}
UnknownFrame::~UnknownFrame()
{
UnknownFrame::~UnknownFrame() {
delete d;
}
String UnknownFrame::toString() const
{
String UnknownFrame::toString() const {
return String();
}
ByteVector UnknownFrame::data() const
{
ByteVector UnknownFrame::data() const {
return d->fieldData;
}
@@ -64,13 +58,11 @@ ByteVector UnknownFrame::data() const
// protected members
////////////////////////////////////////////////////////////////////////////////
void UnknownFrame::parseFields(const ByteVector &data)
{
void UnknownFrame::parseFields(const ByteVector &data) {
d->fieldData = data;
}
ByteVector UnknownFrame::renderFields() const
{
ByteVector UnknownFrame::renderFields() const {
return d->fieldData;
}
@@ -78,9 +70,7 @@ ByteVector UnknownFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
UnknownFrame::UnknownFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new UnknownFramePrivate())
{
UnknownFrame::UnknownFrame(const ByteVector &data, Header *h) : Frame(h),
d(new UnknownFramePrivate()) {
parseFields(fieldData(data));
}

View File

@@ -32,11 +32,11 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
namespace ID3v2 {
//! A frame type \e unknown to TagLib.
//! A frame type \e unknown to TagLib.
/*!
/*!
* This class represents a frame type not known (or more often simply
* unimplemented) in TagLib. This is here provide a basic API for
* manipulating the binary data of unknown frames and to provide a means
@@ -47,35 +47,34 @@ namespace TagLib {
* to have your frame type supported through the standard ID3v2 mechanism.
*/
class TAGLIB_EXPORT UnknownFrame : public Frame
{
friend class FrameFactory;
class TAGLIB_EXPORT UnknownFrame : public Frame {
friend class FrameFactory;
public:
UnknownFrame(const ByteVector &data);
virtual ~UnknownFrame();
public:
UnknownFrame(const ByteVector &data);
virtual ~UnknownFrame();
virtual String toString() const;
virtual String toString() const;
/*!
/*!
* Returns the field data (everything but the header) for this frame.
*/
ByteVector data() const;
ByteVector data() const;
protected:
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
protected:
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
private:
UnknownFrame(const ByteVector &data, Header *h);
UnknownFrame(const UnknownFrame &);
UnknownFrame &operator=(const UnknownFrame &);
private:
UnknownFrame(const ByteVector &data, Header *h);
UnknownFrame(const UnknownFrame &);
UnknownFrame &operator=(const UnknownFrame &);
class UnknownFramePrivate;
UnknownFramePrivate *d;
};
class UnknownFramePrivate;
UnknownFramePrivate *d;
};
}
}
}
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -35,9 +35,8 @@
using namespace Strawberry_TagLib::TagLib;
using namespace ID3v2;
class UnsynchronizedLyricsFrame::UnsynchronizedLyricsFramePrivate
{
public:
class UnsynchronizedLyricsFrame::UnsynchronizedLyricsFramePrivate {
public:
UnsynchronizedLyricsFramePrivate() : textEncoding(String::Latin1) {}
String::Type textEncoding;
ByteVector language;
@@ -49,89 +48,74 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(String::Type encoding) :
Frame("USLT"),
d(new UnsynchronizedLyricsFramePrivate())
{
UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(String::Type encoding) : Frame("USLT"),
d(new UnsynchronizedLyricsFramePrivate()) {
d->textEncoding = encoding;
}
UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(const ByteVector &data) :
Frame(data),
d(new UnsynchronizedLyricsFramePrivate())
{
UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(const ByteVector &data) : Frame(data),
d(new UnsynchronizedLyricsFramePrivate()) {
setData(data);
}
UnsynchronizedLyricsFrame::~UnsynchronizedLyricsFrame()
{
UnsynchronizedLyricsFrame::~UnsynchronizedLyricsFrame() {
delete d;
}
String UnsynchronizedLyricsFrame::toString() const
{
String UnsynchronizedLyricsFrame::toString() const {
return d->text;
}
ByteVector UnsynchronizedLyricsFrame::language() const
{
ByteVector UnsynchronizedLyricsFrame::language() const {
return d->language;
}
String UnsynchronizedLyricsFrame::description() const
{
String UnsynchronizedLyricsFrame::description() const {
return d->description;
}
String UnsynchronizedLyricsFrame::text() const
{
String UnsynchronizedLyricsFrame::text() const {
return d->text;
}
void UnsynchronizedLyricsFrame::setLanguage(const ByteVector &languageEncoding)
{
void UnsynchronizedLyricsFrame::setLanguage(const ByteVector &languageEncoding) {
d->language = languageEncoding.mid(0, 3);
}
void UnsynchronizedLyricsFrame::setDescription(const String &s)
{
void UnsynchronizedLyricsFrame::setDescription(const String &s) {
d->description = s;
}
void UnsynchronizedLyricsFrame::setText(const String &s)
{
void UnsynchronizedLyricsFrame::setText(const String &s) {
d->text = s;
}
String::Type UnsynchronizedLyricsFrame::textEncoding() const
{
String::Type UnsynchronizedLyricsFrame::textEncoding() const {
return d->textEncoding;
}
void UnsynchronizedLyricsFrame::setTextEncoding(String::Type encoding)
{
void UnsynchronizedLyricsFrame::setTextEncoding(String::Type encoding) {
d->textEncoding = encoding;
}
PropertyMap UnsynchronizedLyricsFrame::asProperties() const
{
PropertyMap UnsynchronizedLyricsFrame::asProperties() const {
PropertyMap map;
String key = description().upper();
if(key.isEmpty() || key == "LYRICS")
if (key.isEmpty() || key == "LYRICS")
map.insert("LYRICS", text());
else
map.insert("LYRICS:" + key, text());
return map;
}
UnsynchronizedLyricsFrame *UnsynchronizedLyricsFrame::findByDescription(const ID3v2::Tag *tag, const String &d) // static
UnsynchronizedLyricsFrame *UnsynchronizedLyricsFrame::findByDescription(const ID3v2::Tag *tag, const String &d) // static
{
ID3v2::FrameList lyrics = tag->frameList("USLT");
for(ID3v2::FrameList::ConstIterator it = lyrics.begin(); it != lyrics.end(); ++it){
for (ID3v2::FrameList::ConstIterator it = lyrics.begin(); it != lyrics.end(); ++it) {
UnsynchronizedLyricsFrame *frame = dynamic_cast<UnsynchronizedLyricsFrame *>(*it);
if(frame && frame->description() == d)
if (frame && frame->description() == d)
return frame;
}
return nullptr;
@@ -140,9 +124,8 @@ UnsynchronizedLyricsFrame *UnsynchronizedLyricsFrame::findByDescription(const ID
// protected members
////////////////////////////////////////////////////////////////////////////////
void UnsynchronizedLyricsFrame::parseFields(const ByteVector &data)
{
if(data.size() < 5) {
void UnsynchronizedLyricsFrame::parseFields(const ByteVector &data) {
if (data.size() < 5) {
debug("An unsynchronized lyrics frame must contain at least 5 bytes.");
return;
}
@@ -150,25 +133,24 @@ void UnsynchronizedLyricsFrame::parseFields(const ByteVector &data)
d->textEncoding = String::Type(data[0]);
d->language = data.mid(1, 3);
int byteAlign
= d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
ByteVectorList l =
ByteVectorList::split(data.mid(4), textDelimiter(d->textEncoding), byteAlign, 2);
if(l.size() == 2) {
if(d->textEncoding == String::Latin1) {
if (l.size() == 2) {
if (d->textEncoding == String::Latin1) {
d->description = Tag::latin1StringHandler()->parse(l.front());
d->text = Tag::latin1StringHandler()->parse(l.back());
} else {
}
else {
d->description = String(l.front(), d->textEncoding);
d->text = String(l.back(), d->textEncoding);
}
}
}
ByteVector UnsynchronizedLyricsFrame::renderFields() const
{
ByteVector UnsynchronizedLyricsFrame::renderFields() const {
StringList sl;
sl.append(d->description);
sl.append(d->text);
@@ -190,9 +172,7 @@ ByteVector UnsynchronizedLyricsFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new UnsynchronizedLyricsFramePrivate())
{
UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(const ByteVector &data, Header *h) : Frame(h),
d(new UnsynchronizedLyricsFramePrivate()) {
parseFields(fieldData(data));
}

View File

@@ -33,41 +33,40 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
namespace ID3v2 {
//! ID3v2 unsynchronized lyrics frame
/*!
//! ID3v2 unsynchronized lyrics frame
/*!
* An implementation of ID3v2 unsynchronized lyrics.
*/
class TAGLIB_EXPORT UnsynchronizedLyricsFrame : public Frame
{
friend class FrameFactory;
class TAGLIB_EXPORT UnsynchronizedLyricsFrame : public Frame {
friend class FrameFactory;
public:
/*!
public:
/*!
* Construct an empty unsynchronized lyrics frame that will use the text encoding
* \a encoding.
*/
explicit UnsynchronizedLyricsFrame(String::Type encoding = String::Latin1);
explicit UnsynchronizedLyricsFrame(String::Type encoding = String::Latin1);
/*!
/*!
* Construct a unsynchronized lyrics frame based on the data in \a data.
*/
explicit UnsynchronizedLyricsFrame(const ByteVector &data);
explicit UnsynchronizedLyricsFrame(const ByteVector &data);
/*!
/*!
* Destroys this UnsynchronizedLyricsFrame instance.
*/
virtual ~UnsynchronizedLyricsFrame();
virtual ~UnsynchronizedLyricsFrame();
/*!
/*!
* Returns the text of this unsynchronized lyrics frame.
*
* \see text()
*/
virtual String toString() const;
virtual String toString() const;
/*!
/*!
* Returns the language encoding as a 3 byte encoding as specified by
* <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a>.
*
@@ -75,48 +74,48 @@ namespace TagLib {
*
* \see setLanguage()
*/
ByteVector language() const;
ByteVector language() const;
/*!
/*!
* Returns the description of this unsynchronized lyrics frame.
*
* \note Most taggers simply ignore this value.
*
* \see setDescription()
*/
String description() const;
String description() const;
/*!
/*!
* Returns the text of this unsynchronized lyrics frame.
*
* \see setText()
*/
String text() const;
String text() const;
/*!
/*!
* Set the language using the 3 byte language code from
* <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a> to
* \a languageCode.
*
* \see language()
*/
void setLanguage(const ByteVector &languageCode);
void setLanguage(const ByteVector &languageCode);
/*!
/*!
* Sets the description of the unsynchronized lyrics frame to \a s.
*
* \see description()
*/
void setDescription(const String &s);
void setDescription(const String &s);
/*!
/*!
* Sets the text portion of the unsynchronized lyrics frame to \a s.
*
* \see text()
*/
virtual void setText(const String &s);
virtual void setText(const String &s);
/*!
/*!
* Returns the text encoding that will be used in rendering this frame.
* This defaults to the type that was either specified in the constructor
* or read from the frame when parsed.
@@ -124,19 +123,19 @@ namespace TagLib {
* \see setTextEncoding()
* \see render()
*/
String::Type textEncoding() const;
String::Type textEncoding() const;
/*!
/*!
* Sets the text encoding to be used when rendering this frame to
* \a encoding.
*
* \see textEncoding()
* \see render()
*/
void setTextEncoding(String::Type encoding);
void setTextEncoding(String::Type encoding);
/*! Parses this frame as PropertyMap with a single key.
/*! Parses this frame as PropertyMap with a single key.
* - if description() is empty or "LYRICS", the key will be "LYRICS"
* - if description() is not a valid PropertyMap key, the frame will be
* marked unsupported by an entry "USLT/<description>" in the unsupportedData()
@@ -146,36 +145,36 @@ namespace TagLib {
* Note that currently the language() field is not supported by the PropertyMap
* interface.
*/
PropertyMap asProperties() const;
PropertyMap asProperties() const;
/*!
/*!
* LyricsFrames each have a unique description. This searches for a lyrics
* frame with the description \a d and returns a pointer to it. If no
* frame is found that matches the given description null is returned.
*
* \see description()
*/
static UnsynchronizedLyricsFrame *findByDescription(const Tag *tag, const String &d);
static UnsynchronizedLyricsFrame *findByDescription(const Tag *tag, const String &d);
protected:
// Reimplementations.
protected:
// Reimplementations.
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
private:
/*!
private:
/*!
* The constructor used by the FrameFactory.
*/
UnsynchronizedLyricsFrame(const ByteVector &data, Header *h);
UnsynchronizedLyricsFrame(const UnsynchronizedLyricsFrame &);
UnsynchronizedLyricsFrame &operator=(const UnsynchronizedLyricsFrame &);
UnsynchronizedLyricsFrame(const ByteVector &data, Header *h);
UnsynchronizedLyricsFrame(const UnsynchronizedLyricsFrame &);
UnsynchronizedLyricsFrame &operator=(const UnsynchronizedLyricsFrame &);
class UnsynchronizedLyricsFramePrivate;
UnsynchronizedLyricsFramePrivate *d;
};
class UnsynchronizedLyricsFramePrivate;
UnsynchronizedLyricsFramePrivate *d;
};
}
}
}
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -35,15 +35,13 @@
using namespace Strawberry_TagLib::TagLib;
using namespace ID3v2;
class UrlLinkFrame::UrlLinkFramePrivate
{
public:
class UrlLinkFrame::UrlLinkFramePrivate {
public:
String url;
};
class UserUrlLinkFrame::UserUrlLinkFramePrivate
{
public:
class UserUrlLinkFrame::UserUrlLinkFramePrivate {
public:
UserUrlLinkFramePrivate() : textEncoding(String::Latin1) {}
String::Type textEncoding;
String description;
@@ -53,43 +51,35 @@ public:
// UrlLinkFrame public members
////////////////////////////////////////////////////////////////////////////////
UrlLinkFrame::UrlLinkFrame(const ByteVector &data) :
Frame(data),
d(new UrlLinkFramePrivate())
{
UrlLinkFrame::UrlLinkFrame(const ByteVector &data) : Frame(data),
d(new UrlLinkFramePrivate()) {
setData(data);
}
UrlLinkFrame::~UrlLinkFrame()
{
UrlLinkFrame::~UrlLinkFrame() {
delete d;
}
void UrlLinkFrame::setUrl(const String &s)
{
void UrlLinkFrame::setUrl(const String &s) {
d->url = s;
}
String UrlLinkFrame::url() const
{
String UrlLinkFrame::url() const {
return d->url;
}
void UrlLinkFrame::setText(const String &s)
{
void UrlLinkFrame::setText(const String &s) {
setUrl(s);
}
String UrlLinkFrame::toString() const
{
String UrlLinkFrame::toString() const {
return url();
}
PropertyMap UrlLinkFrame::asProperties() const
{
PropertyMap UrlLinkFrame::asProperties() const {
String key = frameIDToKey(frameID());
PropertyMap map;
if(key.isEmpty())
if (key.isEmpty())
// unknown W*** frame - this normally shouldn't happen
map.unsupportedData().append(frameID());
else
@@ -101,20 +91,16 @@ PropertyMap UrlLinkFrame::asProperties() const
// UrlLinkFrame protected members
////////////////////////////////////////////////////////////////////////////////
void UrlLinkFrame::parseFields(const ByteVector &data)
{
void UrlLinkFrame::parseFields(const ByteVector &data) {
d->url = String(data);
}
ByteVector UrlLinkFrame::renderFields() const
{
ByteVector UrlLinkFrame::renderFields() const {
return d->url.data(String::Latin1);
}
UrlLinkFrame::UrlLinkFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new UrlLinkFramePrivate())
{
UrlLinkFrame::UrlLinkFrame(const ByteVector &data, Header *h) : Frame(h),
d(new UrlLinkFramePrivate()) {
parseFields(fieldData(data));
}
@@ -122,67 +108,56 @@ UrlLinkFrame::UrlLinkFrame(const ByteVector &data, Header *h) :
// UserUrlLinkFrame public members
////////////////////////////////////////////////////////////////////////////////
UserUrlLinkFrame::UserUrlLinkFrame(String::Type encoding) :
UrlLinkFrame("WXXX"),
d(new UserUrlLinkFramePrivate())
{
UserUrlLinkFrame::UserUrlLinkFrame(String::Type encoding) : UrlLinkFrame("WXXX"),
d(new UserUrlLinkFramePrivate()) {
d->textEncoding = encoding;
}
UserUrlLinkFrame::UserUrlLinkFrame(const ByteVector &data) :
UrlLinkFrame(data),
d(new UserUrlLinkFramePrivate())
{
UserUrlLinkFrame::UserUrlLinkFrame(const ByteVector &data) : UrlLinkFrame(data),
d(new UserUrlLinkFramePrivate()) {
setData(data);
}
UserUrlLinkFrame::~UserUrlLinkFrame()
{
UserUrlLinkFrame::~UserUrlLinkFrame() {
delete d;
}
String UserUrlLinkFrame::toString() const
{
String UserUrlLinkFrame::toString() const {
return "[" + description() + "] " + url();
}
String::Type UserUrlLinkFrame::textEncoding() const
{
String::Type UserUrlLinkFrame::textEncoding() const {
return d->textEncoding;
}
void UserUrlLinkFrame::setTextEncoding(String::Type encoding)
{
void UserUrlLinkFrame::setTextEncoding(String::Type encoding) {
d->textEncoding = encoding;
}
String UserUrlLinkFrame::description() const
{
String UserUrlLinkFrame::description() const {
return d->description;
}
void UserUrlLinkFrame::setDescription(const String &s)
{
void UserUrlLinkFrame::setDescription(const String &s) {
d->description = s;
}
PropertyMap UserUrlLinkFrame::asProperties() const
{
PropertyMap UserUrlLinkFrame::asProperties() const {
PropertyMap map;
String key = description().upper();
if(key.isEmpty() || key == "URL")
if (key.isEmpty() || key == "URL")
map.insert("URL", url());
else
map.insert("URL:" + key, url());
return map;
}
UserUrlLinkFrame *UserUrlLinkFrame::find(ID3v2::Tag *tag, const String &description) // static
UserUrlLinkFrame *UserUrlLinkFrame::find(ID3v2::Tag *tag, const String &description) // static
{
FrameList l = tag->frameList("WXXX");
for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it) {
for (FrameList::ConstIterator it = l.begin(); it != l.end(); ++it) {
UserUrlLinkFrame *f = dynamic_cast<UserUrlLinkFrame *>(*it);
if(f && f->description() == description)
if (f && f->description() == description)
return f;
}
return nullptr;
@@ -192,9 +167,8 @@ UserUrlLinkFrame *UserUrlLinkFrame::find(ID3v2::Tag *tag, const String &descript
// UserUrlLinkFrame protected members
////////////////////////////////////////////////////////////////////////////////
void UserUrlLinkFrame::parseFields(const ByteVector &data)
{
if(data.size() < 2) {
void UserUrlLinkFrame::parseFields(const ByteVector &data) {
if (data.size() < 2) {
debug("A user URL link frame must contain at least 2 bytes.");
return;
}
@@ -204,9 +178,9 @@ void UserUrlLinkFrame::parseFields(const ByteVector &data)
d->textEncoding = String::Type(data[0]);
pos += 1;
if(d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8) {
if (d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8) {
int offset = data.find(textDelimiter(d->textEncoding), pos);
if(offset < pos)
if (offset < pos)
return;
d->description = String(data.mid(pos, offset - pos), d->textEncoding);
@@ -214,7 +188,7 @@ void UserUrlLinkFrame::parseFields(const ByteVector &data)
}
else {
int len = data.mid(pos).find(textDelimiter(d->textEncoding), 0, 2);
if(len < 0)
if (len < 0)
return;
d->description = String(data.mid(pos, len), d->textEncoding);
@@ -224,8 +198,7 @@ void UserUrlLinkFrame::parseFields(const ByteVector &data)
setUrl(String(data.mid(pos)));
}
ByteVector UserUrlLinkFrame::renderFields() const
{
ByteVector UserUrlLinkFrame::renderFields() const {
ByteVector v;
String::Type encoding = checkTextEncoding(d->description, d->textEncoding);
@@ -238,9 +211,7 @@ ByteVector UserUrlLinkFrame::renderFields() const
return v;
}
UserUrlLinkFrame::UserUrlLinkFrame(const ByteVector &data, Header *h) :
UrlLinkFrame(data, h),
d(new UserUrlLinkFramePrivate())
{
UserUrlLinkFrame::UserUrlLinkFrame(const ByteVector &data, Header *h) : UrlLinkFrame(data, h),
d(new UserUrlLinkFramePrivate()) {
parseFields(fieldData(data));
}

View File

@@ -34,97 +34,95 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
namespace ID3v2 {
//! ID3v2 URL frame
/*!
//! ID3v2 URL frame
/*!
* An implementation of ID3v2 URL link frames.
*/
class TAGLIB_EXPORT UrlLinkFrame : public Frame
{
friend class FrameFactory;
class TAGLIB_EXPORT UrlLinkFrame : public Frame {
friend class FrameFactory;
public:
/*!
public:
/*!
* This is a dual purpose constructor. \a data can either be binary data
* that should be parsed or (at a minimum) the frame ID.
*/
explicit UrlLinkFrame(const ByteVector &data);
explicit UrlLinkFrame(const ByteVector &data);
/*!
/*!
* Destroys this UrlLinkFrame instance.
*/
virtual ~UrlLinkFrame();
virtual ~UrlLinkFrame();
/*!
/*!
* Returns the URL.
*/
virtual String url() const;
virtual String url() const;
/*!
/*!
* Sets the URL to \a s.
*/
virtual void setUrl(const String &s);
virtual void setUrl(const String &s);
// Reimplementations.
// Reimplementations.
virtual void setText(const String &s);
virtual String toString() const;
PropertyMap asProperties() const;
virtual void setText(const String &s);
virtual String toString() const;
PropertyMap asProperties() const;
protected:
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
protected:
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
/*!
/*!
* The constructor used by the FrameFactory.
*/
UrlLinkFrame(const ByteVector &data, Header *h);
UrlLinkFrame(const ByteVector &data, Header *h);
private:
UrlLinkFrame(const UrlLinkFrame &);
UrlLinkFrame &operator=(const UrlLinkFrame &);
private:
UrlLinkFrame(const UrlLinkFrame &);
UrlLinkFrame &operator=(const UrlLinkFrame &);
class UrlLinkFramePrivate;
UrlLinkFramePrivate *d;
};
class UrlLinkFramePrivate;
UrlLinkFramePrivate *d;
};
//! ID3v2 User defined URL frame
//! ID3v2 User defined URL frame
/*!
/*!
* This is a specialization of URL link frames that allows for
* user defined entries. Each entry has a description in addition to the
* normal list of fields that a URL link frame has.
*
* This description identifies the frame and must be unique.
*/
class TAGLIB_EXPORT UserUrlLinkFrame : public UrlLinkFrame
{
friend class FrameFactory;
class TAGLIB_EXPORT UserUrlLinkFrame : public UrlLinkFrame {
friend class FrameFactory;
public:
/*!
public:
/*!
* Constructs an empty user defined URL link frame. For this to be
* a useful frame both a description and text must be set.
*/
explicit UserUrlLinkFrame(String::Type encoding = String::Latin1);
explicit UserUrlLinkFrame(String::Type encoding = String::Latin1);
/*!
/*!
* This is a dual purpose constructor. \a data can either be binary data
* that should be parsed or (at a minimum) the frame ID.
*/
explicit UserUrlLinkFrame(const ByteVector &data);
explicit UserUrlLinkFrame(const ByteVector &data);
/*!
/*!
* Destroys this UserUrlLinkFrame instance.
*/
virtual ~UserUrlLinkFrame();
virtual ~UserUrlLinkFrame();
// Reimplementations.
// Reimplementations.
virtual String toString() const;
virtual String toString() const;
/*!
/*!
* Returns the text encoding that will be used in rendering this frame.
* This defaults to the type that was either specified in the constructor
* or read from the frame when parsed.
@@ -132,28 +130,28 @@ namespace TagLib {
* \see setTextEncoding()
* \see render()
*/
String::Type textEncoding() const;
String::Type textEncoding() const;
/*!
/*!
* Sets the text encoding to be used when rendering this frame to
* \a encoding.
*
* \see textEncoding()
* \see render()
*/
void setTextEncoding(String::Type encoding);
void setTextEncoding(String::Type encoding);
/*!
/*!
* Returns the description for this frame.
*/
String description() const;
String description() const;
/*!
/*!
* Sets the description of the frame to \a s. \a s must be unique.
*/
void setDescription(const String &s);
void setDescription(const String &s);
/*!
/*!
* Parses the UserUrlLinkFrame as PropertyMap. The description() is taken as key,
* and the URL as single value.
* - if description() is empty, the key will be "URL".
@@ -161,32 +159,32 @@ namespace TagLib {
* characters), the returned map will contain an entry "WXXX/<description>"
* in its unsupportedData() list.
*/
PropertyMap asProperties() const;
PropertyMap asProperties() const;
/*!
/*!
* Searches for the user defined url frame with the description \a description
* in \a tag. This returns null if no matching frames were found.
*/
static UserUrlLinkFrame *find(Tag *tag, const String &description);
static UserUrlLinkFrame *find(Tag *tag, const String &description);
protected:
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
protected:
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
/*!
/*!
* The constructor used by the FrameFactory.
*/
UserUrlLinkFrame(const ByteVector &data, Header *h);
UserUrlLinkFrame(const ByteVector &data, Header *h);
private:
UserUrlLinkFrame(const UserUrlLinkFrame &);
UserUrlLinkFrame &operator=(const UserUrlLinkFrame &);
private:
UserUrlLinkFrame(const UserUrlLinkFrame &);
UserUrlLinkFrame &operator=(const UserUrlLinkFrame &);
class UserUrlLinkFramePrivate;
UserUrlLinkFramePrivate *d;
};
class UserUrlLinkFramePrivate;
UserUrlLinkFramePrivate *d;
};
}
}
}
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -3,24 +3,24 @@
namespace Strawberry_TagLib {
namespace TagLib {
//! An ID3v2 implementation
//! An ID3v2 implementation
/*!
/*!
* This is a relatively complete and flexible framework for working with ID3v2
* tags.
*
* \see ID3v2::Tag
*/
namespace ID3v2 {
/*!
namespace ID3v2 {
/*!
* Used to specify which version of the ID3 standard to use when saving tags.
*/
enum Version {
v3 = 3, //<! ID3v2.3
v4 = 4 //<! ID3v2.4
};
}
}
}
enum Version {
v3 = 3, //<! ID3v2.3
v4 = 4 //<! ID3v2.4
};
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -29,9 +29,8 @@
using namespace Strawberry_TagLib::TagLib;
using namespace ID3v2;
class ExtendedHeader::ExtendedHeaderPrivate
{
public:
class ExtendedHeader::ExtendedHeaderPrivate {
public:
ExtendedHeaderPrivate() : size(0) {}
unsigned int size;
@@ -41,23 +40,18 @@ public:
// public methods
////////////////////////////////////////////////////////////////////////////////
ExtendedHeader::ExtendedHeader() :
d(new ExtendedHeaderPrivate())
{
ExtendedHeader::ExtendedHeader() : d(new ExtendedHeaderPrivate()) {
}
ExtendedHeader::~ExtendedHeader()
{
ExtendedHeader::~ExtendedHeader() {
delete d;
}
unsigned int ExtendedHeader::size() const
{
unsigned int ExtendedHeader::size() const {
return d->size;
}
void ExtendedHeader::setData(const ByteVector &data)
{
void ExtendedHeader::setData(const ByteVector &data) {
parse(data);
}
@@ -65,7 +59,6 @@ void ExtendedHeader::setData(const ByteVector &data)
// protected members
////////////////////////////////////////////////////////////////////////////////
void ExtendedHeader::parse(const ByteVector &data)
{
d->size = SynchData::toUInt(data.mid(0, 4)); // (structure 3.2 "Extended header size")
void ExtendedHeader::parse(const ByteVector &data) {
d->size = SynchData::toUInt(data.mid(0, 4)); // (structure 3.2 "Extended header size")
}

View File

@@ -33,11 +33,11 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
namespace ID3v2 {
//! ID3v2 extended header implementation
//! ID3v2 extended header implementation
/*!
/*!
* This class implements ID3v2 extended headers. It attempts to follow,
* both semantically and programmatically, the structure specified in
* the ID3v2 standard. The API is based on the properties of ID3v2 extended
@@ -46,50 +46,49 @@ namespace TagLib {
* (Structure, <a href="id3v2-structure.html#3.2">3.2</a>)
*/
class TAGLIB_EXPORT ExtendedHeader
{
public:
/*!
class TAGLIB_EXPORT ExtendedHeader {
public:
/*!
* Constructs an empty ID3v2 extended header.
*/
ExtendedHeader();
ExtendedHeader();
/*!
/*!
* Destroys the extended header.
*/
virtual ~ExtendedHeader();
virtual ~ExtendedHeader();
/*!
/*!
* Returns the size of the extended header. This is variable for the
* extended header.
*/
unsigned int size() const;
unsigned int size() const;
/*!
/*!
* Sets the data that will be used as the extended header. Since the
* length is not known before the extended header has been parsed, this
* should just be a pointer to the first byte of the extended header. It
* will determine the length internally and make that available through
* size().
*/
void setData(const ByteVector &data);
void setData(const ByteVector &data);
protected:
/*!
protected:
/*!
* Called by setData() to parse the extended header data. It makes this
* information available through the public API.
*/
void parse(const ByteVector &data);
void parse(const ByteVector &data);
private:
ExtendedHeader(const ExtendedHeader &);
ExtendedHeader &operator=(const ExtendedHeader &);
private:
ExtendedHeader(const ExtendedHeader &);
ExtendedHeader &operator=(const ExtendedHeader &);
class ExtendedHeaderPrivate;
ExtendedHeaderPrivate *d;
};
class ExtendedHeaderPrivate;
ExtendedHeaderPrivate *d;
};
}
}
}
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -29,26 +29,20 @@
using namespace Strawberry_TagLib::TagLib;
using namespace ID3v2;
class Footer::FooterPrivate
{
class Footer::FooterPrivate {
};
Footer::Footer() :
d(0)
{
Footer::Footer() : d(0) {
}
Footer::~Footer()
{
Footer::~Footer() {
}
unsigned int Footer::size()
{
unsigned int Footer::size() {
return 10;
}
ByteVector Footer::render(const Header *header) const
{
ByteVector Footer::render(const Header *header) const {
ByteVector headerData = header->render();
headerData[0] = '3';
headerData[1] = 'D';

View File

@@ -32,13 +32,13 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
namespace ID3v2 {
class Header;
class Header;
//! ID3v2 footer implementation
//! ID3v2 footer implementation
/*!
/*!
* Per the ID3v2 specification, the tag's footer is just a copy of the
* information in the header. As such there is no API for reading the
* data from the header, it can just as easily be done from the header.
@@ -48,37 +48,36 @@ namespace TagLib {
* has been set in the ID3v2::Tag, TagLib will render a footer.
*/
class TAGLIB_EXPORT Footer
{
public:
/*!
class TAGLIB_EXPORT Footer {
public:
/*!
* Constructs an empty ID3v2 footer.
*/
Footer();
/*!
Footer();
/*!
* Destroys the footer.
*/
virtual ~Footer();
virtual ~Footer();
/*!
/*!
* Returns the size of the footer. Presently this is always 10 bytes.
*/
static unsigned int size();
static unsigned int size();
/*!
/*!
* Renders the footer based on the data in \a header.
*/
ByteVector render(const Header *header) const;
ByteVector render(const Header *header) const;
private:
Footer(const Footer &);
Footer &operator=(const Footer &);
private:
Footer(const Footer &);
Footer &operator=(const Footer &);
class FooterPrivate;
FooterPrivate *d;
};
class FooterPrivate;
FooterPrivate *d;
};
}
}
}
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -33,17 +33,17 @@
namespace Strawberry_TagLib {
namespace TagLib {
class StringList;
class PropertyMap;
class StringList;
class PropertyMap;
namespace ID3v2 {
namespace ID3v2 {
class Tag;
class FrameFactory;
class Tag;
class FrameFactory;
//! ID3v2 frame implementation
//! ID3v2 frame implementation
/*!
/*!
* This class is the main ID3v2 frame implementation. In ID3v2, a tag is
* split between a collection of frames (which are in turn split into fields
* (Structure, <a href="id3v2-structure.html#4">4</a>)
@@ -52,37 +52,35 @@ namespace TagLib {
* specific to a given frame type is handed in one of the many subclasses.
*/
class TAGLIB_EXPORT Frame
{
friend class Tag;
friend class FrameFactory;
class TAGLIB_EXPORT Frame {
friend class Tag;
friend class FrameFactory;
public:
/*!
public:
/*!
* Creates a textual frame which corresponds to a single key in the PropertyMap
* interface. These are all (User)TextIdentificationFrames except TIPL and TMCL,
* all (User)URLLinkFrames, CommentsFrames, and UnsynchronizedLyricsFrame.
*/
static Frame *createTextualFrame(const String &key, const StringList &values);
static Frame *createTextualFrame(const String &key, const StringList &values);
/*!
/*!
* Destroys this Frame instance.
*/
virtual ~Frame();
virtual ~Frame();
/*!
/*!
* Returns the Frame ID (Structure, <a href="id3v2-structure.html#4">4</a>)
* (Frames, <a href="id3v2-frames.html#4">4</a>)
*/
ByteVector frameID() const;
ByteVector frameID() const;
/*!
/*!
* Returns the size of the frame.
*/
unsigned int size() const;
unsigned int size() const;
/*!
/*!
* Returns the size of the frame header
*
* \deprecated This is only accurate for ID3v2.3 or ID3v2.4. Please use
@@ -90,25 +88,25 @@ namespace TagLib {
* non-binary compatible release this will be made into a non-static
* member that checks the internal ID3v2 version.
*/
static unsigned int headerSize(); // BIC: make non-static
static unsigned int headerSize(); // BIC: make non-static
/*!
/*!
* Returns the size of the frame header for the given ID3v2 version.
*
* \deprecated Please see the explanation above.
*/
// BIC: remove
static unsigned int headerSize(unsigned int version);
// BIC: remove
static unsigned int headerSize(unsigned int version);
/*!
/*!
* Sets the data that will be used as the frame. Since the length is not
* known before the frame has been parsed, this should just be a pointer to
* the first byte of the frame. It will determine the length internally
* and make that available through size().
*/
void setData(const ByteVector &data);
void setData(const ByteVector &data);
/*!
/*!
* Set the text of frame in the sanest way possible. This should only be
* reimplemented in frames where there is some logical mapping to text.
*
@@ -117,176 +115,176 @@ namespace TagLib {
* that frame's encoding. Please use the specific APIs of the frame types
* to set the encoding if that is desired.
*/
virtual void setText(const String &text);
virtual void setText(const String &text);
/*!
/*!
* This returns the textual representation of the data in the frame.
* Subclasses must reimplement this method to provide a string
* representation of the frame's data.
*/
virtual String toString() const = 0;
virtual String toString() const = 0;
/*!
/*!
* Render the frame back to its binary format in a ByteVector.
*/
ByteVector render() const;
ByteVector render() const;
/*!
/*!
* Returns the text delimiter that is used between fields for the string
* type \a t.
*/
static ByteVector textDelimiter(String::Type t);
static ByteVector textDelimiter(String::Type t);
/*!
/*!
* The string with which an instrument name is prefixed to build a key in a PropertyMap;
* used to translate PropertyMaps to TMCL frames. In the current implementation, this
* is "PERFORMER:".
*/
static const String instrumentPrefix;
/*!
static const String instrumentPrefix;
/*!
* The PropertyMap key prefix which triggers the use of a COMM frame instead of a TXXX
* frame for a non-standard key. In the current implementation, this is "COMMENT:".
*/
static const String commentPrefix;
/*!
static const String commentPrefix;
/*!
* The PropertyMap key prefix which triggers the use of a USLT frame instead of a TXXX
* frame for a non-standard key. In the current implementation, this is "LYRICS:".
*/
static const String lyricsPrefix;
/*!
static const String lyricsPrefix;
/*!
* The PropertyMap key prefix which triggers the use of a WXXX frame instead of a TXX
* frame for a non-standard key. In the current implementation, this is "URL:".
*/
static const String urlPrefix;
static const String urlPrefix;
protected:
class Header;
protected:
class Header;
/*!
/*!
* Constructs an ID3v2 frame using \a data to read the header information.
* All other processing of \a data should be handled in a subclass.
*
* \note This need not contain anything more than a frame ID, but
* \e must contain at least that.
*/
explicit Frame(const ByteVector &data);
explicit Frame(const ByteVector &data);
/*!
/*!
* This creates an Frame using the header \a h.
*
* The ownership of this header will be assigned to the frame and the
* header will be deleted when the frame is destroyed.
*/
Frame(Header *h);
Frame(Header *h);
/*!
/*!
* Returns a pointer to the frame header.
*/
Header *header() const;
Header *header() const;
/*!
/*!
* Sets the header to \a h. If \a deleteCurrent is true, this will free
* the memory of the current header.
*
* The ownership of this header will be assigned to the frame and the
* header will be deleted when the frame is destroyed.
*/
void setHeader(Header *h, bool deleteCurrent = true);
void setHeader(Header *h, bool deleteCurrent = true);
/*!
/*!
* Called by setData() to parse the frame data. It makes this information
* available through the public API.
*/
void parse(const ByteVector &data);
void parse(const ByteVector &data);
/*!
/*!
* Called by parse() to parse the field data. It makes this information
* available through the public API. This must be overridden by the
* subclasses.
*/
virtual void parseFields(const ByteVector &data) = 0;
virtual void parseFields(const ByteVector &data) = 0;
/*!
/*!
* Render the field data back to a binary format in a ByteVector. This
* must be overridden by subclasses.
*/
virtual ByteVector renderFields() const = 0;
virtual ByteVector renderFields() const = 0;
/*!
/*!
* Returns a ByteVector containing the field data given the frame data.
* This correctly adjusts for the header size plus any additional frame
* data that's specified in the frame header flags.
*/
ByteVector fieldData(const ByteVector &frameData) const;
ByteVector fieldData(const ByteVector &frameData) const;
/*!
/*!
* Reads a String of type \a encoding from the ByteVector \a data. If \a
* position is passed in it is used both as the starting point and is
* updated to return the position just after the string that has been read.
* This is useful for reading strings sequentially.
*/
String readStringField(const ByteVector &data, String::Type encoding,
int *position = 0);
String readStringField(const ByteVector &data, String::Type encoding,
int *position = 0);
/*!
/*!
* Checks a the list of string values to see if they can be used with the
* specified encoding and returns the recommended encoding.
*/
// BIC: remove and make non-static
static String::Type checkEncoding(const StringList &fields,
String::Type encoding);
// BIC: remove and make non-static
static String::Type checkEncoding(const StringList &fields,
String::Type encoding);
/*!
/*!
* Checks a the list of string values to see if they can be used with the
* specified encoding and returns the recommended encoding. This method
* also checks the ID3v2 version and makes sure the encoding can be used
* in the specified version.
*/
// BIC: remove and make non-static
static String::Type checkEncoding(const StringList &fields,
String::Type encoding, unsigned int version);
// BIC: remove and make non-static
static String::Type checkEncoding(const StringList &fields,
String::Type encoding, unsigned int version);
/*!
/*!
* Checks a the list of string values to see if they can be used with the
* specified encoding and returns the recommended encoding. This method
* also checks the ID3v2 version and makes sure the encoding can be used
* in the version specified by the frame's header.
*/
String::Type checkTextEncoding(const StringList &fields,
String::Type encoding) const;
String::Type checkTextEncoding(const StringList &fields,
String::Type encoding) const;
/*!
/*!
* Parses the contents of this frame as PropertyMap. If that fails, the returned
* PropertyMap will be empty, and its unsupportedData() will contain this frame's
* ID.
* BIC: Will be a virtual function in future releases.
*/
PropertyMap asProperties() const;
PropertyMap asProperties() const;
/*!
/*!
* Returns an appropriate ID3 frame ID for the given free-form tag key. This method
* will return an empty ByteVector if no specialized translation is found.
*/
static ByteVector keyToFrameID(const String &);
static ByteVector keyToFrameID(const String &);
/*!
/*!
* Returns a free-form tag name for the given ID3 frame ID. Note that this does not work
* for general frame IDs such as TXXX or WXXX; in such a case an empty string is returned.
*/
static String frameIDToKey(const ByteVector &);
static String frameIDToKey(const ByteVector &);
/*!
/*!
* Returns an appropriate TXXX frame description for the given free-form tag key.
*/
static String keyToTXXX(const String &);
static String keyToTXXX(const String &);
/*!
/*!
* Returns a free-form tag name for the given ID3 frame description.
*/
static String txxxToKey(const String &);
static String txxxToKey(const String &);
/*!
/*!
* This helper function splits the PropertyMap \a original into three ProperytMaps
* \a singleFrameProperties, \a tiplProperties, and \a tmclProperties, such that:
* - \a singleFrameProperties contains only of keys which can be represented with
@@ -299,21 +297,21 @@ namespace TagLib {
* - \a tmclProperties contains the "musician credits" keys which should be mapped
* to a TMCL frame
*/
static void splitProperties(const PropertyMap &original, PropertyMap &singleFrameProperties,
PropertyMap &tiplProperties, PropertyMap &tmclProperties);
static void splitProperties(const PropertyMap &original, PropertyMap &singleFrameProperties,
PropertyMap &tiplProperties, PropertyMap &tmclProperties);
private:
Frame(const Frame &);
Frame &operator=(const Frame &);
private:
Frame(const Frame &);
Frame &operator=(const Frame &);
class FramePrivate;
friend class FramePrivate;
FramePrivate *d;
};
class FramePrivate;
friend class FramePrivate;
FramePrivate *d;
};
//! ID3v2 frame header implementation
//! ID3v2 frame header implementation
/*!
/*!
* The ID3v2 Frame Header (Structure, <a href="id3v2-structure.html#4">4</a>)
*
* Every ID3v2::Frame has an associated header that gives some general
@@ -325,10 +323,9 @@ namespace TagLib {
* the type and attaches the header.
*/
class TAGLIB_EXPORT Frame::Header
{
public:
/*!
class TAGLIB_EXPORT Frame::Header {
public:
/*!
* Construct a Frame Header based on \a data. \a data must at least
* contain a 4 byte frame ID, and optionally can contain flag data and the
* frame size. i.e. Just the frame id -- "TALB" -- is a valid value.
@@ -336,43 +333,43 @@ namespace TagLib {
* \deprecated Please use the constructor below that accepts a version
* number.
*/
TAGLIB_DEPRECATED Header(const ByteVector &data, bool synchSafeInts);
TAGLIB_DEPRECATED Header(const ByteVector &data, bool synchSafeInts);
/*!
/*!
* Construct a Frame Header based on \a data. \a data must at least
* contain a 4 byte frame ID, and optionally can contain flag data and the
* frame size. i.e. Just the frame id -- "TALB" -- is a valid value.
*
* \a version should be the ID3v2 version of the tag.
*/
explicit Header(const ByteVector &data, unsigned int version = 4);
explicit Header(const ByteVector &data, unsigned int version = 4);
/*!
/*!
* Destroys this Header instance.
*/
virtual ~Header();
virtual ~Header();
/*!
/*!
* Sets the data for the Header.
*
* \deprecated Please use the version below that accepts an ID3v2 version
* number.
*/
void setData(const ByteVector &data, bool synchSafeInts);
void setData(const ByteVector &data, bool synchSafeInts);
/*!
/*!
* Sets the data for the Header. \a version should indicate the ID3v2
* version number of the tag that this frame is contained in.
*/
void setData(const ByteVector &data, unsigned int version = 4);
void setData(const ByteVector &data, unsigned int version = 4);
/*!
/*!
* Returns the Frame ID (Structure, <a href="id3v2-structure.html#4">4</a>)
* (Frames, <a href="id3v2-frames.html#4">4</a>)
*/
ByteVector frameID() const;
ByteVector frameID() const;
/*!
/*!
* Sets the frame's ID to \a id. Only the first four bytes of \a id will
* be used.
*
@@ -380,32 +377,32 @@ namespace TagLib {
* provide a mechanism for transforming frames from a deprecated frame type
* to a newer one -- i.e. TYER to TDRC from ID3v2.3 to ID3v2.4.
*/
void setFrameID(const ByteVector &id);
void setFrameID(const ByteVector &id);
/*!
/*!
* Returns the size of the frame data portion, as set when setData() was
* called or set explicitly via setFrameSize().
*/
unsigned int frameSize() const;
unsigned int frameSize() const;
/*!
/*!
* Sets the size of the frame data portion.
*/
void setFrameSize(unsigned int size);
void setFrameSize(unsigned int size);
/*!
/*!
* Returns the ID3v2 version of the header, as passed in from the
* construction of the header or set via setVersion().
*/
unsigned int version() const;
unsigned int version() const;
/*!
/*!
* Sets the ID3v2 version of the header, changing has impact on the
* correct parsing/rendering of frame data.
*/
void setVersion(unsigned int version);
void setVersion(unsigned int version);
/*!
/*!
* Returns the size of the frame header in bytes.
*
* \deprecated Please use the version of this method that accepts a
@@ -413,19 +410,19 @@ namespace TagLib {
* removed in the next binary incompatible release (2.0) and will be
* replaced with a non-static method that checks the frame version.
*/
// BIC: make non-static
static unsigned int size();
// BIC: make non-static
static unsigned int size();
/*!
/*!
* Returns the size of the frame header in bytes for the ID3v2 version
* that's given.
*
* \deprecated Please see the explanation in the version above.
*/
// BIC: remove
static unsigned int size(unsigned int version);
// BIC: remove
static unsigned int size(unsigned int version);
/*!
/*!
* Returns true if the flag for tag alter preservation is set.
*
* The semantics are a little backwards from what would seem natural
@@ -434,9 +431,9 @@ namespace TagLib {
*
* \see setTagAlterPreservation()
*/
bool tagAlterPreservation() const;
bool tagAlterPreservation() const;
/*!
/*!
* Sets the flag for preservation of this frame if the tag is set. If
* this is set to true the frame will not be written when the tag is
* saved.
@@ -447,77 +444,77 @@ namespace TagLib {
*
* \see tagAlterPreservation()
*/
void setTagAlterPreservation(bool discard);
void setTagAlterPreservation(bool discard);
/*!
/*!
* Returns true if the flag for file alter preservation is set.
*
* \note This flag is currently ignored internally in TagLib.
*/
bool fileAlterPreservation() const;
bool fileAlterPreservation() const;
/*!
/*!
* Returns true if the frame is meant to be read only.
*
* \note This flag is currently ignored internally in TagLib.
*/
bool readOnly() const;
bool readOnly() const;
/*!
/*!
* Returns true if the flag for the grouping identity is set.
*
* \note This flag is currently ignored internally in TagLib.
*/
bool groupingIdentity() const;
bool groupingIdentity() const;
/*!
/*!
* Returns true if compression is enabled for this frame.
*
* \note This flag is currently ignored internally in TagLib.
*/
bool compression() const;
bool compression() const;
/*!
/*!
* Returns true if encryption is enabled for this frame.
*
* \note This flag is currently ignored internally in TagLib.
*/
bool encryption() const;
bool encryption() const;
#ifndef DO_NOT_DOCUMENT
bool unsycronisation() const;
bool unsycronisation() const;
#endif
/*!
/*!
* Returns true if unsynchronisation is enabled for this frame.
*/
bool unsynchronisation() const;
bool unsynchronisation() const;
/*!
/*!
* Returns true if the flag for a data length indicator is set.
*/
bool dataLengthIndicator() const;
bool dataLengthIndicator() const;
/*!
/*!
* Render the Header back to binary format in a ByteVector.
*/
ByteVector render() const;
ByteVector render() const;
/*!
/*!
* \deprecated
*/
TAGLIB_DEPRECATED bool frameAlterPreservation() const;
TAGLIB_DEPRECATED bool frameAlterPreservation() const;
private:
Header(const Header &);
Header &operator=(const Header &);
private:
Header(const Header &);
Header &operator=(const Header &);
class HeaderPrivate;
HeaderPrivate *d;
};
class HeaderPrivate;
HeaderPrivate *d;
};
}
}
}
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -51,53 +51,48 @@
using namespace Strawberry_TagLib::TagLib;
using namespace ID3v2;
namespace
{
void updateGenre(TextIdentificationFrame *frame)
{
StringList fields = frame->fieldList();
StringList newfields;
namespace {
void updateGenre(TextIdentificationFrame *frame) {
StringList fields = frame->fieldList();
StringList newfields;
for(StringList::ConstIterator it = fields.begin(); it != fields.end(); ++it) {
String s = *it;
int end = s.find(")");
for (StringList::ConstIterator it = fields.begin(); it != fields.end(); ++it) {
String s = *it;
int end = s.find(")");
if(s.startsWith("(") && end > 0) {
// "(12)Genre"
String text = s.substr(end + 1);
bool ok;
int number = s.substr(1, end - 1).toInt(&ok);
if(ok && number >= 0 && number <= 255 && !(ID3v1::genre(number) == text))
newfields.append(s.substr(1, end - 1));
if(!text.isEmpty())
newfields.append(text);
}
else {
// "Genre" or "12"
newfields.append(s);
}
if (s.startsWith("(") && end > 0) {
// "(12)Genre"
String text = s.substr(end + 1);
bool ok;
int number = s.substr(1, end - 1).toInt(&ok);
if (ok && number >= 0 && number <= 255 && !(ID3v1::genre(number) == text))
newfields.append(s.substr(1, end - 1));
if (!text.isEmpty())
newfields.append(text);
}
else {
// "Genre" or "12"
newfields.append(s);
}
if(newfields.isEmpty())
fields.append(String());
frame->setText(newfields);
}
}
class FrameFactory::FrameFactoryPrivate
{
public:
FrameFactoryPrivate() :
defaultEncoding(String::Latin1),
useDefaultEncoding(false) {}
if (newfields.isEmpty())
fields.append(String());
frame->setText(newfields);
}
} // namespace
class FrameFactory::FrameFactoryPrivate {
public:
FrameFactoryPrivate() : defaultEncoding(String::Latin1),
useDefaultEncoding(false) {}
String::Type defaultEncoding;
bool useDefaultEncoding;
template <class T> void setTextEncoding(T *frame)
{
if(useDefaultEncoding)
template<class T> void setTextEncoding(T *frame) {
if (useDefaultEncoding)
frame->setTextEncoding(defaultEncoding);
}
};
@@ -108,30 +103,25 @@ FrameFactory FrameFactory::factory;
// public members
////////////////////////////////////////////////////////////////////////////////
FrameFactory *FrameFactory::instance()
{
FrameFactory *FrameFactory::instance() {
return &factory;
}
Frame *FrameFactory::createFrame(const ByteVector &data, bool synchSafeInts) const
{
Frame *FrameFactory::createFrame(const ByteVector &data, bool synchSafeInts) const {
return createFrame(data, static_cast<unsigned int>(synchSafeInts ? 4 : 3));
}
Frame *FrameFactory::createFrame(const ByteVector &data, unsigned int version) const
{
Frame *FrameFactory::createFrame(const ByteVector &data, unsigned int version) const {
Header tagHeader;
tagHeader.setMajorVersion(version);
return createFrame(data, &tagHeader);
}
Frame *FrameFactory::createFrame(const ByteVector &origData, Header *tagHeader) const
{
return createFrame(origData, const_cast<const Header *>(tagHeader));
Frame *FrameFactory::createFrame(const ByteVector &origData, Header *tagHeader) const {
return createFrame(origData, const_cast<const Header *>(tagHeader));
}
Frame *FrameFactory::createFrame(const ByteVector &origData, const Header *tagHeader) const
{
Frame *FrameFactory::createFrame(const ByteVector &origData, const Header *tagHeader) const {
ByteVector data = origData;
unsigned int version = tagHeader->majorVersion();
Frame::Header *header = new Frame::Header(data, version);
@@ -140,16 +130,15 @@ Frame *FrameFactory::createFrame(const ByteVector &origData, const Header *tagHe
// A quick sanity check -- make sure that the frameID is 4 uppercase Latin1
// characters. Also make sure that there is data in the frame.
if(frameID.size() != (version < 3 ? 3 : 4) ||
header->frameSize() <= static_cast<unsigned int>(header->dataLengthIndicator() ? 4 : 0) ||
header->frameSize() > data.size())
{
if (frameID.size() != (version < 3 ? 3 : 4) ||
header->frameSize() <= static_cast<unsigned int>(header->dataLengthIndicator() ? 4 : 0) ||
header->frameSize() > data.size()) {
delete header;
return nullptr;
}
#ifndef NO_ITUNES_HACKS
if(version == 3 && frameID.size() == 4 && frameID[3] == '\0') {
if (version == 3 && frameID.size() == 4 && frameID[3] == '\0') {
// iTunes v2.3 tags store v2.2 frames - convert now
frameID = frameID.mid(0, 3);
header->setFrameID(frameID);
@@ -159,14 +148,14 @@ Frame *FrameFactory::createFrame(const ByteVector &origData, const Header *tagHe
}
#endif
for(ByteVector::ConstIterator it = frameID.begin(); it != frameID.end(); it++) {
if( (*it < 'A' || *it > 'Z') && (*it < '0' || *it > '9') ) {
for (ByteVector::ConstIterator it = frameID.begin(); it != frameID.end(); it++) {
if ((*it < 'A' || *it > 'Z') && (*it < '0' || *it > '9')) {
delete header;
return nullptr;
}
}
if(version > 3 && (tagHeader->unsynchronisation() || header->unsynchronisation())) {
if (version > 3 && (tagHeader->unsynchronisation() || header->unsynchronisation())) {
// Data lengths are not part of the encoded data, but since they are synch-safe
// integers they will be never actually encoded.
ByteVector frameData = data.mid(Frame::Header::size(version), header->frameSize());
@@ -177,17 +166,17 @@ Frame *FrameFactory::createFrame(const ByteVector &origData, const Header *tagHe
// TagLib doesn't mess with encrypted frames, so just treat them
// as unknown frames.
if(!zlib::isAvailable() && header->compression()) {
if (!zlib::isAvailable() && header->compression()) {
debug("Compressed frames are currently not supported.");
return new UnknownFrame(data, header);
}
if(header->encryption()) {
if (header->encryption()) {
debug("Encrypted frames are currently not supported.");
return new UnknownFrame(data, header);
}
if(!updateFrame(header)) {
if (!updateFrame(header)) {
header->setTagAlterPreservation(true);
return new UnknownFrame(data, header);
}
@@ -204,15 +193,13 @@ Frame *FrameFactory::createFrame(const ByteVector &origData, const Header *tagHe
// Text Identification (frames 4.2)
// Apple proprietary WFED (Podcast URL), MVNM (Movement Name), MVIN (Movement Number), GRP1 (Grouping) are in fact text frames.
if(frameID.startsWith("T") || frameID == "WFED" || frameID == "MVNM" || frameID == "MVIN" || frameID == "GRP1") {
if (frameID.startsWith("T") || frameID == "WFED" || frameID == "MVNM" || frameID == "MVIN" || frameID == "GRP1") {
TextIdentificationFrame *f = frameID != "TXXX"
? new TextIdentificationFrame(data, header)
: new UserTextIdentificationFrame(data, header);
TextIdentificationFrame *f = frameID != "TXXX" ? new TextIdentificationFrame(data, header) : new UserTextIdentificationFrame(data, header);
d->setTextEncoding(f);
if(frameID == "TCON")
if (frameID == "TCON")
updateGenre(f);
return f;
@@ -220,7 +207,7 @@ Frame *FrameFactory::createFrame(const ByteVector &origData, const Header *tagHe
// Comments (frames 4.10)
if(frameID == "COMM") {
if (frameID == "COMM") {
CommentsFrame *f = new CommentsFrame(data, header);
d->setTextEncoding(f);
return f;
@@ -228,7 +215,7 @@ Frame *FrameFactory::createFrame(const ByteVector &origData, const Header *tagHe
// Attached Picture (frames 4.14)
if(frameID == "APIC") {
if (frameID == "APIC") {
AttachedPictureFrame *f = new AttachedPictureFrame(data, header);
d->setTextEncoding(f);
return f;
@@ -236,7 +223,7 @@ Frame *FrameFactory::createFrame(const ByteVector &origData, const Header *tagHe
// ID3v2.2 Attached Picture
if(frameID == "PIC") {
if (frameID == "PIC") {
AttachedPictureFrame *f = new AttachedPictureFrameV22(data, header);
d->setTextEncoding(f);
return f;
@@ -244,17 +231,17 @@ Frame *FrameFactory::createFrame(const ByteVector &origData, const Header *tagHe
// Relative Volume Adjustment (frames 4.11)
if(frameID == "RVA2")
if (frameID == "RVA2")
return new RelativeVolumeFrame(data, header);
// Unique File Identifier (frames 4.1)
if(frameID == "UFID")
if (frameID == "UFID")
return new UniqueFileIdentifierFrame(data, header);
// General Encapsulated Object (frames 4.15)
if(frameID == "GEOB") {
if (frameID == "GEOB") {
GeneralEncapsulatedObjectFrame *f = new GeneralEncapsulatedObjectFrame(data, header);
d->setTextEncoding(f);
return f;
@@ -262,8 +249,8 @@ Frame *FrameFactory::createFrame(const ByteVector &origData, const Header *tagHe
// URL link (frames 4.3)
if(frameID.startsWith("W")) {
if(frameID != "WXXX") {
if (frameID.startsWith("W")) {
if (frameID != "WXXX") {
return new UrlLinkFrame(data, header);
}
else {
@@ -275,40 +262,40 @@ Frame *FrameFactory::createFrame(const ByteVector &origData, const Header *tagHe
// Unsynchronized lyric/text transcription (frames 4.8)
if(frameID == "USLT") {
if (frameID == "USLT") {
UnsynchronizedLyricsFrame *f = new UnsynchronizedLyricsFrame(data, header);
if(d->useDefaultEncoding)
if (d->useDefaultEncoding)
f->setTextEncoding(d->defaultEncoding);
return f;
}
// Synchronised lyrics/text (frames 4.9)
if(frameID == "SYLT") {
if (frameID == "SYLT") {
SynchronizedLyricsFrame *f = new SynchronizedLyricsFrame(data, header);
if(d->useDefaultEncoding)
if (d->useDefaultEncoding)
f->setTextEncoding(d->defaultEncoding);
return f;
}
// Event timing codes (frames 4.5)
if(frameID == "ETCO")
if (frameID == "ETCO")
return new EventTimingCodesFrame(data, header);
// Popularimeter (frames 4.17)
if(frameID == "POPM")
if (frameID == "POPM")
return new PopularimeterFrame(data, header);
// Private (frames 4.27)
if(frameID == "PRIV")
if (frameID == "PRIV")
return new PrivateFrame(data, header);
// Ownership (frames 4.22)
if(frameID == "OWNE") {
if (frameID == "OWNE") {
OwnershipFrame *f = new OwnershipFrame(data, header);
d->setTextEncoding(f);
return f;
@@ -316,45 +303,42 @@ Frame *FrameFactory::createFrame(const ByteVector &origData, const Header *tagHe
// Chapter (ID3v2 chapters 1.0)
if(frameID == "CHAP")
if (frameID == "CHAP")
return new ChapterFrame(tagHeader, data, header);
// Table of contents (ID3v2 chapters 1.0)
if(frameID == "CTOC")
if (frameID == "CTOC")
return new TableOfContentsFrame(tagHeader, data, header);
// Apple proprietary PCST (Podcast)
if(frameID == "PCST")
if (frameID == "PCST")
return new PodcastFrame(data, header);
return new UnknownFrame(data, header);
}
void FrameFactory::rebuildAggregateFrames(ID3v2::Tag *tag) const
{
if(tag->header()->majorVersion() < 4 &&
tag->frameList("TDRC").size() == 1 &&
tag->frameList("TDAT").size() == 1)
{
void FrameFactory::rebuildAggregateFrames(ID3v2::Tag *tag) const {
if (tag->header()->majorVersion() < 4 &&
tag->frameList("TDRC").size() == 1 &&
tag->frameList("TDAT").size() == 1) {
TextIdentificationFrame *tdrc =
dynamic_cast<TextIdentificationFrame *>(tag->frameList("TDRC").front());
UnknownFrame *tdat = static_cast<UnknownFrame *>(tag->frameList("TDAT").front());
if(tdrc &&
tdrc->fieldList().size() == 1 &&
tdrc->fieldList().front().size() == 4 &&
tdat->data().size() >= 5)
{
if (tdrc &&
tdrc->fieldList().size() == 1 &&
tdrc->fieldList().front().size() == 4 &&
tdat->data().size() >= 5) {
String date(tdat->data().mid(1), String::Type(tdat->data()[0]));
if(date.length() == 4) {
if (date.length() == 4) {
tdrc->setText(tdrc->toString() + '-' + date.substr(2, 2) + '-' + date.substr(0, 2));
if(tag->frameList("TIME").size() == 1) {
if (tag->frameList("TIME").size() == 1) {
UnknownFrame *timeframe = static_cast<UnknownFrame *>(tag->frameList("TIME").front());
if(timeframe->data().size() >= 5) {
if (timeframe->data().size() >= 5) {
String time(timeframe->data().mid(1), String::Type(timeframe->data()[0]));
if(time.length() == 4) {
if (time.length() == 4) {
tdrc->setText(tdrc->toString() + 'T' + time.substr(0, 2) + ':' + time.substr(2, 2));
}
}
@@ -364,13 +348,11 @@ void FrameFactory::rebuildAggregateFrames(ID3v2::Tag *tag) const
}
}
String::Type FrameFactory::defaultTextEncoding() const
{
String::Type FrameFactory::defaultTextEncoding() const {
return d->defaultEncoding;
}
void FrameFactory::setDefaultTextEncoding(String::Type encoding)
{
void FrameFactory::setDefaultTextEncoding(String::Type encoding) {
d->useDefaultEncoding = true;
d->defaultEncoding = encoding;
}
@@ -379,171 +361,164 @@ void FrameFactory::setDefaultTextEncoding(String::Type encoding)
// protected members
////////////////////////////////////////////////////////////////////////////////
FrameFactory::FrameFactory() :
d(new FrameFactoryPrivate())
{
FrameFactory::FrameFactory() : d(new FrameFactoryPrivate()) {
}
FrameFactory::~FrameFactory()
{
FrameFactory::~FrameFactory() {
delete d;
}
namespace
{
// Frame conversion table ID3v2.2 -> 2.4
const char *frameConversion2[][2] = {
{ "BUF", "RBUF" },
{ "CNT", "PCNT" },
{ "COM", "COMM" },
{ "CRA", "AENC" },
{ "ETC", "ETCO" },
{ "GEO", "GEOB" },
{ "IPL", "TIPL" },
{ "MCI", "MCDI" },
{ "MLL", "MLLT" },
{ "POP", "POPM" },
{ "REV", "RVRB" },
{ "SLT", "SYLT" },
{ "STC", "SYTC" },
{ "TAL", "TALB" },
{ "TBP", "TBPM" },
{ "TCM", "TCOM" },
{ "TCO", "TCON" },
{ "TCP", "TCMP" },
{ "TCR", "TCOP" },
{ "TDY", "TDLY" },
{ "TEN", "TENC" },
{ "TFT", "TFLT" },
{ "TKE", "TKEY" },
{ "TLA", "TLAN" },
{ "TLE", "TLEN" },
{ "TMT", "TMED" },
{ "TOA", "TOAL" },
{ "TOF", "TOFN" },
{ "TOL", "TOLY" },
{ "TOR", "TDOR" },
{ "TOT", "TOAL" },
{ "TP1", "TPE1" },
{ "TP2", "TPE2" },
{ "TP3", "TPE3" },
{ "TP4", "TPE4" },
{ "TPA", "TPOS" },
{ "TPB", "TPUB" },
{ "TRC", "TSRC" },
{ "TRD", "TDRC" },
{ "TRK", "TRCK" },
{ "TS2", "TSO2" },
{ "TSA", "TSOA" },
{ "TSC", "TSOC" },
{ "TSP", "TSOP" },
{ "TSS", "TSSE" },
{ "TST", "TSOT" },
{ "TT1", "TIT1" },
{ "TT2", "TIT2" },
{ "TT3", "TIT3" },
{ "TXT", "TOLY" },
{ "TXX", "TXXX" },
{ "TYE", "TDRC" },
{ "UFI", "UFID" },
{ "ULT", "USLT" },
{ "WAF", "WOAF" },
{ "WAR", "WOAR" },
{ "WAS", "WOAS" },
{ "WCM", "WCOM" },
{ "WCP", "WCOP" },
{ "WPB", "WPUB" },
{ "WXX", "WXXX" },
namespace {
// Frame conversion table ID3v2.2 -> 2.4
const char *frameConversion2[][2] = {
{ "BUF", "RBUF" },
{ "CNT", "PCNT" },
{ "COM", "COMM" },
{ "CRA", "AENC" },
{ "ETC", "ETCO" },
{ "GEO", "GEOB" },
{ "IPL", "TIPL" },
{ "MCI", "MCDI" },
{ "MLL", "MLLT" },
{ "POP", "POPM" },
{ "REV", "RVRB" },
{ "SLT", "SYLT" },
{ "STC", "SYTC" },
{ "TAL", "TALB" },
{ "TBP", "TBPM" },
{ "TCM", "TCOM" },
{ "TCO", "TCON" },
{ "TCP", "TCMP" },
{ "TCR", "TCOP" },
{ "TDY", "TDLY" },
{ "TEN", "TENC" },
{ "TFT", "TFLT" },
{ "TKE", "TKEY" },
{ "TLA", "TLAN" },
{ "TLE", "TLEN" },
{ "TMT", "TMED" },
{ "TOA", "TOAL" },
{ "TOF", "TOFN" },
{ "TOL", "TOLY" },
{ "TOR", "TDOR" },
{ "TOT", "TOAL" },
{ "TP1", "TPE1" },
{ "TP2", "TPE2" },
{ "TP3", "TPE3" },
{ "TP4", "TPE4" },
{ "TPA", "TPOS" },
{ "TPB", "TPUB" },
{ "TRC", "TSRC" },
{ "TRD", "TDRC" },
{ "TRK", "TRCK" },
{ "TS2", "TSO2" },
{ "TSA", "TSOA" },
{ "TSC", "TSOC" },
{ "TSP", "TSOP" },
{ "TSS", "TSSE" },
{ "TST", "TSOT" },
{ "TT1", "TIT1" },
{ "TT2", "TIT2" },
{ "TT3", "TIT3" },
{ "TXT", "TOLY" },
{ "TXX", "TXXX" },
{ "TYE", "TDRC" },
{ "UFI", "UFID" },
{ "ULT", "USLT" },
{ "WAF", "WOAF" },
{ "WAR", "WOAR" },
{ "WAS", "WOAS" },
{ "WCM", "WCOM" },
{ "WCP", "WCOP" },
{ "WPB", "WPUB" },
{ "WXX", "WXXX" },
// Apple iTunes nonstandard frames
{ "PCS", "PCST" },
{ "TCT", "TCAT" },
{ "TDR", "TDRL" },
{ "TDS", "TDES" },
{ "TID", "TGID" },
{ "WFD", "WFED" },
{ "MVN", "MVNM" },
{ "MVI", "MVIN" },
{ "GP1", "GRP1" },
};
const size_t frameConversion2Size = sizeof(frameConversion2) / sizeof(frameConversion2[0]);
// Apple iTunes nonstandard frames
{ "PCS", "PCST" },
{ "TCT", "TCAT" },
{ "TDR", "TDRL" },
{ "TDS", "TDES" },
{ "TID", "TGID" },
{ "WFD", "WFED" },
{ "MVN", "MVNM" },
{ "MVI", "MVIN" },
{ "GP1", "GRP1" },
};
const size_t frameConversion2Size = sizeof(frameConversion2) / sizeof(frameConversion2[0]);
// Frame conversion table ID3v2.3 -> 2.4
const char *frameConversion3[][2] = {
{ "TORY", "TDOR" },
{ "TYER", "TDRC" },
{ "IPLS", "TIPL" },
};
const size_t frameConversion3Size = sizeof(frameConversion3) / sizeof(frameConversion3[0]);
}
// Frame conversion table ID3v2.3 -> 2.4
const char *frameConversion3[][2] = {
{ "TORY", "TDOR" },
{ "TYER", "TDRC" },
{ "IPLS", "TIPL" },
};
const size_t frameConversion3Size = sizeof(frameConversion3) / sizeof(frameConversion3[0]);
} // namespace
bool FrameFactory::updateFrame(Frame::Header *header) const
{
bool FrameFactory::updateFrame(Frame::Header *header) const {
const ByteVector frameID = header->frameID();
switch(header->version()) {
switch (header->version()) {
case 2: // ID3v2.2
{
if(frameID == "CRM" ||
frameID == "EQU" ||
frameID == "LNK" ||
frameID == "RVA" ||
frameID == "TIM" ||
frameID == "TSI" ||
frameID == "TDA")
case 2: // ID3v2.2
{
debug("ID3v2.4 no longer supports the frame type " + String(frameID) +
". It will be discarded from the tag.");
return false;
}
// ID3v2.2 only used 3 bytes for the frame ID, so we need to convert all of
// the frames to their 4 byte ID3v2.4 equivalent.
for(size_t i = 0; i < frameConversion2Size; ++i) {
if(frameID == frameConversion2[i][0]) {
header->setFrameID(frameConversion2[i][1]);
break;
if (frameID == "CRM" ||
frameID == "EQU" ||
frameID == "LNK" ||
frameID == "RVA" ||
frameID == "TIM" ||
frameID == "TSI" ||
frameID == "TDA") {
debug("ID3v2.4 no longer supports the frame type " + String(frameID) +
". It will be discarded from the tag.");
return false;
}
// ID3v2.2 only used 3 bytes for the frame ID, so we need to convert all of
// the frames to their 4 byte ID3v2.4 equivalent.
for (size_t i = 0; i < frameConversion2Size; ++i) {
if (frameID == frameConversion2[i][0]) {
header->setFrameID(frameConversion2[i][1]);
break;
}
}
break;
}
break;
}
case 3: // ID3v2.3
{
if(frameID == "EQUA" ||
frameID == "RVAD" ||
frameID == "TIME" ||
frameID == "TRDA" ||
frameID == "TSIZ" ||
frameID == "TDAT")
case 3: // ID3v2.3
{
debug("ID3v2.4 no longer supports the frame type " + String(frameID) +
". It will be discarded from the tag.");
return false;
}
for(size_t i = 0; i < frameConversion3Size; ++i) {
if(frameID == frameConversion3[i][0]) {
header->setFrameID(frameConversion3[i][1]);
break;
if (frameID == "EQUA" ||
frameID == "RVAD" ||
frameID == "TIME" ||
frameID == "TRDA" ||
frameID == "TSIZ" ||
frameID == "TDAT") {
debug("ID3v2.4 no longer supports the frame type " + String(frameID) +
". It will be discarded from the tag.");
return false;
}
for (size_t i = 0; i < frameConversion3Size; ++i) {
if (frameID == frameConversion3[i][0]) {
header->setFrameID(frameConversion3[i][1]);
break;
}
}
break;
}
break;
}
default:
default:
// This should catch a typo that existed in TagLib up to and including
// version 1.1 where TRDC was used for the year rather than TDRC.
// This should catch a typo that existed in TagLib up to and including
// version 1.1 where TRDC was used for the year rather than TDRC.
if (frameID == "TRDC")
header->setFrameID("TDRC");
if(frameID == "TRDC")
header->setFrameID("TDRC");
break;
break;
}
return true;

View File

@@ -1,4 +1,4 @@
/***************************************************************************
/***************************************************************************
copyright : (C) 2002 - 2008 by Scott Wheeler
email : wheeler@kde.org
***************************************************************************/
@@ -34,13 +34,13 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
namespace ID3v2 {
class TextIdentificationFrame;
class TextIdentificationFrame;
//! A factory for creating ID3v2 frames during parsing
//! A factory for creating ID3v2 frames during parsing
/*!
/*!
* This factory abstracts away the frame creation process and instantiates
* the appropriate ID3v2::Frame subclasses based on the contents of the
* data.
@@ -63,11 +63,10 @@ namespace TagLib {
* \see ID3v2::Tag::addFrame()
*/
class TAGLIB_EXPORT FrameFactory
{
public:
static FrameFactory *instance();
/*!
class TAGLIB_EXPORT FrameFactory {
public:
static FrameFactory *instance();
/*!
* Create a frame based on \a data. \a synchSafeInts should only be set
* false if we are parsing an old tag (v2.3 or older) that does not support
* synchsafe ints.
@@ -75,9 +74,9 @@ namespace TagLib {
* \deprecated Please use the method below that accepts a ID3v2::Header
* instance in new code.
*/
Frame *createFrame(const ByteVector &data, bool synchSafeInts) const;
Frame *createFrame(const ByteVector &data, bool synchSafeInts) const;
/*!
/*!
* Create a frame based on \a data. \a version should indicate the ID3v2
* version of the tag. As ID3v2.4 is the most current version of the
* standard 4 is the default.
@@ -85,29 +84,29 @@ namespace TagLib {
* \deprecated Please use the method below that accepts a ID3v2::Header
* instance in new code.
*/
Frame *createFrame(const ByteVector &data, unsigned int version = 4) const;
Frame *createFrame(const ByteVector &data, unsigned int version = 4) const;
/*!
/*!
* \deprecated
*/
// BIC: remove
Frame *createFrame(const ByteVector &data, Header *tagHeader) const;
/*!
// BIC: remove
Frame *createFrame(const ByteVector &data, Header *tagHeader) const;
/*!
* Create a frame based on \a data. \a tagHeader should be a valid
* ID3v2::Header instance.
*/
// BIC: make virtual
Frame *createFrame(const ByteVector &data, const Header *tagHeader) const;
// BIC: make virtual
Frame *createFrame(const ByteVector &data, const Header *tagHeader) const;
/*!
/*!
* After a tag has been read, this tries to rebuild some of them
* information, most notably the recording date, from frames that
* have been deprecated and can't be upgraded directly.
*/
// BIC: Make virtual
void rebuildAggregateFrames(ID3v2::Tag *tag) const;
// BIC: Make virtual
void rebuildAggregateFrames(ID3v2::Tag *tag) const;
/*!
/*!
* Returns the default text encoding for text frames. If setTextEncoding()
* has not been explicitly called this will only be used for new text
* frames. However, if this value has been set explicitly all frames will be
@@ -116,9 +115,9 @@ namespace TagLib {
*
* \see setDefaultTextEncoding()
*/
String::Type defaultTextEncoding() const;
String::Type defaultTextEncoding() const;
/*!
/*!
* Set the default text encoding for all text frames that are created to
* \a encoding. If no value is set the frames with either default to the
* encoding type that was parsed and new frames default to Latin1.
@@ -127,21 +126,21 @@ namespace TagLib {
*
* \see defaultTextEncoding()
*/
void setDefaultTextEncoding(String::Type encoding);
void setDefaultTextEncoding(String::Type encoding);
protected:
/*!
protected:
/*!
* Constructs a frame factory. Because this is a singleton this method is
* protected, but may be used for subclasses.
*/
FrameFactory();
FrameFactory();
/*!
/*!
* Destroys the frame factory.
*/
virtual ~FrameFactory();
virtual ~FrameFactory();
/*!
/*!
* This method checks for compliance to the current ID3v2 standard (2.4)
* and does nothing in the common case. However if a frame is found that
* is not compatible with the current standard, this method either updates
@@ -152,20 +151,20 @@ namespace TagLib {
*
* See the id3v2.4.0-changes.txt document for further information.
*/
virtual bool updateFrame(Frame::Header *header) const;
virtual bool updateFrame(Frame::Header *header) const;
private:
FrameFactory(const FrameFactory &);
FrameFactory &operator=(const FrameFactory &);
private:
FrameFactory(const FrameFactory &);
FrameFactory &operator=(const FrameFactory &);
static FrameFactory factory;
static FrameFactory factory;
class FrameFactoryPrivate;
FrameFactoryPrivate *d;
};
class FrameFactoryPrivate;
FrameFactoryPrivate *d;
};
}
}
}
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -36,17 +36,15 @@
using namespace Strawberry_TagLib::TagLib;
using namespace ID3v2;
class Header::HeaderPrivate
{
public:
HeaderPrivate() :
majorVersion(4),
revisionNumber(0),
unsynchronisation(false),
extendedHeader(false),
experimentalIndicator(false),
footerPresent(false),
tagSize(0) {}
class Header::HeaderPrivate {
public:
HeaderPrivate() : majorVersion(4),
revisionNumber(0),
unsynchronisation(false),
extendedHeader(false),
experimentalIndicator(false),
footerPresent(false),
tagSize(0) {}
unsigned int majorVersion;
unsigned int revisionNumber;
@@ -63,13 +61,11 @@ public:
// static members
////////////////////////////////////////////////////////////////////////////////
unsigned int Header::size()
{
unsigned int Header::size() {
return 10;
}
ByteVector Header::fileIdentifier()
{
ByteVector Header::fileIdentifier() {
return ByteVector::fromCString("ID3");
}
@@ -77,82 +73,65 @@ ByteVector Header::fileIdentifier()
// public members
////////////////////////////////////////////////////////////////////////////////
Header::Header() :
d(new HeaderPrivate())
{
Header::Header() : d(new HeaderPrivate()) {
}
Header::Header(const ByteVector &data) :
d(new HeaderPrivate())
{
Header::Header(const ByteVector &data) : d(new HeaderPrivate()) {
parse(data);
}
Header::~Header()
{
Header::~Header() {
delete d;
}
unsigned int Header::majorVersion() const
{
unsigned int Header::majorVersion() const {
return d->majorVersion;
}
void Header::setMajorVersion(unsigned int version)
{
void Header::setMajorVersion(unsigned int version) {
d->majorVersion = version;
}
unsigned int Header::revisionNumber() const
{
unsigned int Header::revisionNumber() const {
return d->revisionNumber;
}
bool Header::unsynchronisation() const
{
bool Header::unsynchronisation() const {
return d->unsynchronisation;
}
bool Header::extendedHeader() const
{
bool Header::extendedHeader() const {
return d->extendedHeader;
}
bool Header::experimentalIndicator() const
{
bool Header::experimentalIndicator() const {
return d->experimentalIndicator;
}
bool Header::footerPresent() const
{
bool Header::footerPresent() const {
return d->footerPresent;
}
unsigned int Header::tagSize() const
{
unsigned int Header::tagSize() const {
return d->tagSize;
}
unsigned int Header::completeTagSize() const
{
if(d->footerPresent)
unsigned int Header::completeTagSize() const {
if (d->footerPresent)
return d->tagSize + size() + Footer::size();
else
return d->tagSize + size();
}
void Header::setTagSize(unsigned int s)
{
void Header::setTagSize(unsigned int s) {
d->tagSize = s;
}
void Header::setData(const ByteVector &data)
{
void Header::setData(const ByteVector &data) {
parse(data);
}
ByteVector Header::render() const
{
ByteVector Header::render() const {
ByteVector v;
// add the file identifier -- "ID3"
@@ -191,9 +170,8 @@ ByteVector Header::render() const
// protected members
////////////////////////////////////////////////////////////////////////////////
void Header::parse(const ByteVector &data)
{
if(data.size() < size())
void Header::parse(const ByteVector &data) {
if (data.size() < size())
return;
// do some sanity checking -- even in ID3v2.3.0 and less the tag size is a
@@ -205,14 +183,14 @@ void Header::parse(const ByteVector &data)
ByteVector sizeData = data.mid(6, 4);
if(sizeData.size() != 4) {
if (sizeData.size() != 4) {
d->tagSize = 0;
debug("TagLib::ID3v2::Header::parse() - The tag size as read was 0 bytes!");
return;
}
for(ByteVector::ConstIterator it = sizeData.begin(); it != sizeData.end(); it++) {
if(static_cast<unsigned char>(*it) >= 128) {
for (ByteVector::ConstIterator it = sizeData.begin(); it != sizeData.end(); it++) {
if (static_cast<unsigned char>(*it) >= 128) {
d->tagSize = 0;
debug("TagLib::ID3v2::Header::parse() - One of the size bytes in the id3v2 header was greater than the allowed 128.");
return;
@@ -222,18 +200,18 @@ void Header::parse(const ByteVector &data)
// The first three bytes, data[0..2], are the File Identifier, "ID3". (structure 3.1 "file identifier")
// Read the version number from the fourth and fifth bytes.
d->majorVersion = data[3]; // (structure 3.1 "major version")
d->revisionNumber = data[4]; // (structure 3.1 "revision number")
d->majorVersion = data[3]; // (structure 3.1 "major version")
d->revisionNumber = data[4]; // (structure 3.1 "revision number")
// Read the flags, the first four bits of the sixth byte.
std::bitset<8> flags(data[5]);
d->unsynchronisation = flags[7]; // (structure 3.1.a)
d->extendedHeader = flags[6]; // (structure 3.1.b)
d->experimentalIndicator = flags[5]; // (structure 3.1.c)
d->footerPresent = flags[4]; // (structure 3.1.d)
d->unsynchronisation = flags[7]; // (structure 3.1.a)
d->extendedHeader = flags[6]; // (structure 3.1.b)
d->experimentalIndicator = flags[5]; // (structure 3.1.c)
d->footerPresent = flags[4]; // (structure 3.1.d)
// Get the size from the remaining four bytes (read above)
d->tagSize = SynchData::toUInt(sizeData); // (structure 3.1 "size")
d->tagSize = SynchData::toUInt(sizeData); // (structure 3.1 "size")
}

View File

@@ -33,11 +33,11 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
namespace ID3v2 {
//! An implementation of ID3v2 headers
//! An implementation of ID3v2 headers
/*!
/*!
* This class implements ID3v2 headers. It attempts to follow, both
* semantically and programmatically, the structure specified in
* the ID3v2 standard. The API is based on the properties of ID3v2 headers
@@ -46,32 +46,31 @@ namespace TagLib {
* (Structure, <a href="id3v2-structure.html#3.1">3.1</a>)
*/
class TAGLIB_EXPORT Header
{
public:
/*!
class TAGLIB_EXPORT Header {
public:
/*!
* Constructs an empty ID3v2 header.
*/
Header();
Header();
/*!
/*!
* Constructs an ID3v2 header based on \a data. parse() is called
* immediately.
*/
Header(const ByteVector &data);
Header(const ByteVector &data);
/*!
/*!
* Destroys the header.
*/
virtual ~Header();
virtual ~Header();
/*!
/*!
* Returns the major version number. (Note: This is the 4, not the 2 in
* ID3v2.4.0. The 2 is implied.)
*/
unsigned int majorVersion() const;
unsigned int majorVersion() const;
/*!
/*!
* Set the the major version number to \a version. (Note: This is
* the 4, not the 2 in ID3v2.4.0. The 2 is implied.)
* \see majorVersion()
@@ -80,34 +79,34 @@ namespace TagLib {
* version which is written and in general should not be called by API
* users.
*/
void setMajorVersion(unsigned int version);
void setMajorVersion(unsigned int version);
/*!
/*!
* Returns the revision number. (Note: This is the 0, not the 4 in
* ID3v2.4.0. The 2 is implied.)
*/
unsigned int revisionNumber() const;
unsigned int revisionNumber() const;
/*!
/*!
* Returns true if unsynchronisation has been applied to all frames.
*/
bool unsynchronisation() const;
bool unsynchronisation() const;
/*!
/*!
* Returns true if an extended header is present in the tag.
*/
bool extendedHeader() const;
bool extendedHeader() const;
/*!
/*!
* Returns true if the experimental indicator flag is set.
*/
bool experimentalIndicator() const;
bool experimentalIndicator() const;
/*!
/*!
* Returns true if a footer is present in the tag.
*/
bool footerPresent() const;
/*!
bool footerPresent() const;
/*!
* Returns the tag size in bytes. This is the size of the frame content.
* The size of the \e entire tag will be this plus the header size (10
* bytes) and, if present, the footer size (potentially another 10 bytes).
@@ -118,61 +117,61 @@ namespace TagLib {
*
* \see completeTagSize()
*/
unsigned int tagSize() const;
unsigned int tagSize() const;
/*!
/*!
* Returns the tag size, including the header and, if present, the footer
* size.
*
* \see tagSize()
*/
unsigned int completeTagSize() const;
unsigned int completeTagSize() const;
/*!
/*!
* Set the tag size to \a s.
* \see tagSize()
*/
void setTagSize(unsigned int s);
void setTagSize(unsigned int s);
/*!
/*!
* Returns the size of the header. Presently this is always 10 bytes.
*/
static unsigned int size();
static unsigned int size();
/*!
/*!
* Returns the string used to identify and ID3v2 tag inside of a file.
* Presently this is always "ID3".
*/
static ByteVector fileIdentifier();
static ByteVector fileIdentifier();
/*!
/*!
* Sets the data that will be used as the header. 10 bytes, starting from
* the beginning of \a data are used.
*/
void setData(const ByteVector &data);
void setData(const ByteVector &data);
/*!
/*!
* Renders the Header back to binary format.
*/
ByteVector render() const;
ByteVector render() const;
protected:
/*!
protected:
/*!
* Called by setData() to parse the header data. It makes this information
* available through the public API.
*/
void parse(const ByteVector &data);
void parse(const ByteVector &data);
private:
Header(const Header &);
Header &operator=(const Header &);
private:
Header(const Header &);
Header &operator=(const Header &);
class HeaderPrivate;
HeaderPrivate *d;
};
class HeaderPrivate;
HeaderPrivate *d;
};
}
}
}
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -30,14 +30,13 @@
using namespace Strawberry_TagLib::TagLib;
using namespace ID3v2;
unsigned int SynchData::toUInt(const ByteVector &data)
{
unsigned int SynchData::toUInt(const ByteVector &data) {
unsigned int sum = 0;
bool notSynchSafe = false;
int last = data.size() > 4 ? 3 : data.size() - 1;
for(int i = 0; i <= last; i++) {
if(data[i] & 0x80) {
for (int i = 0; i <= last; i++) {
if (data[i] & 0x80) {
notSynchSafe = true;
break;
}
@@ -45,11 +44,11 @@ unsigned int SynchData::toUInt(const ByteVector &data)
sum |= (data[i] & 0x7f) << ((last - i) * 7);
}
if(notSynchSafe) {
if (notSynchSafe) {
// Invalid data; assume this was created by some buggy software that just
// put normal integers here rather than syncsafe ones, and try it that
// way.
if(data.size() >= 4) {
if (data.size() >= 4) {
sum = data.toUInt(0, true);
}
else {
@@ -62,18 +61,16 @@ unsigned int SynchData::toUInt(const ByteVector &data)
return sum;
}
ByteVector SynchData::fromUInt(unsigned int value)
{
ByteVector SynchData::fromUInt(unsigned int value) {
ByteVector v(4, 0);
for(int i = 0; i < 4; i++)
for (int i = 0; i < 4; i++)
v[i] = static_cast<unsigned char>(value >> ((3 - i) * 7) & 0x7f);
return v;
}
ByteVector SynchData::decode(const ByteVector &data)
{
ByteVector SynchData::decode(const ByteVector &data) {
// We have this optimized method instead of using ByteVector::replace(),
// since it makes a great difference when decoding huge unsynchronized frames.
@@ -82,14 +79,14 @@ ByteVector SynchData::decode(const ByteVector &data)
ByteVector::ConstIterator src = data.begin();
ByteVector::Iterator dst = result.begin();
while(src < data.end() - 1) {
while (src < data.end() - 1) {
*dst++ = *src++;
if(*(src - 1) == '\xff' && *src == '\x00')
if (*(src - 1) == '\xff' && *src == '\x00')
src++;
}
if(src < data.end())
if (src < data.end())
*dst++ = *src++;
result.resize(static_cast<unsigned int>(dst - result.begin()));

View File

@@ -32,11 +32,11 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 {
namespace ID3v2 {
//! A few functions for ID3v2 synch safe integer conversion
//! A few functions for ID3v2 synch safe integer conversion
/*!
/*!
* In the ID3v2.4 standard most integer values are encoded as "synch safe"
* integers which are encoded in such a way that they will not give false
* MPEG syncs and confuse MPEG decoders. This namespace provides some
@@ -44,29 +44,28 @@ namespace TagLib {
* things rendering and parsing ID3v2 data.
*/
namespace SynchData
{
/*!
namespace SynchData {
/*!
* This returns the unsigned integer value of \a data where \a data is a
* ByteVector that contains a \e synchsafe integer (Structure,
* <a href="id3v2-structure.html#6.2">6.2</a>). The default \a length of
* 4 is used if another value is not specified.
*/
TAGLIB_EXPORT unsigned int toUInt(const ByteVector &data);
TAGLIB_EXPORT unsigned int toUInt(const ByteVector &data);
/*!
/*!
* Returns a 4 byte (32 bit) synchsafe integer based on \a value.
*/
TAGLIB_EXPORT ByteVector fromUInt(unsigned int value);
TAGLIB_EXPORT ByteVector fromUInt(unsigned int value);
/*!
/*!
* Convert the data from unsynchronized data to its original format.
*/
TAGLIB_EXPORT ByteVector decode(const ByteVector &input);
}
TAGLIB_EXPORT ByteVector decode(const ByteVector &input);
} // namespace SynchData
}
}
}
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -47,30 +47,25 @@
using namespace Strawberry_TagLib::TagLib;
using namespace ID3v2;
namespace
{
const ID3v2::Latin1StringHandler defaultStringHandler;
const ID3v2::Latin1StringHandler *stringHandler = &defaultStringHandler;
namespace {
const ID3v2::Latin1StringHandler defaultStringHandler;
const ID3v2::Latin1StringHandler *stringHandler = &defaultStringHandler;
const long MinPaddingSize = 1024;
const long MaxPaddingSize = 1024 * 1024;
}
const long MinPaddingSize = 1024;
const long MaxPaddingSize = 1024 * 1024;
} // namespace
class ID3v2::Tag::TagPrivate
{
public:
TagPrivate() :
factory(0),
file(0),
tagOffset(0),
extendedHeader(0),
footer(0)
{
class ID3v2::Tag::TagPrivate {
public:
TagPrivate() : factory(0),
file(0),
tagOffset(0),
extendedHeader(0),
footer(0) {
frameList.setAutoDelete(true);
}
~TagPrivate()
{
~TagPrivate() {
delete extendedHeader;
delete footer;
}
@@ -92,16 +87,13 @@ public:
// StringHandler implementation
////////////////////////////////////////////////////////////////////////////////
Latin1StringHandler::Latin1StringHandler()
{
Latin1StringHandler::Latin1StringHandler() {
}
Latin1StringHandler::~Latin1StringHandler()
{
Latin1StringHandler::~Latin1StringHandler() {
}
String Latin1StringHandler::parse(const ByteVector &data) const
{
String Latin1StringHandler::parse(const ByteVector &data) const {
return String(data, String::Latin1);
}
@@ -109,17 +101,13 @@ String Latin1StringHandler::parse(const ByteVector &data) const
// public members
////////////////////////////////////////////////////////////////////////////////
ID3v2::Tag::Tag() :
Strawberry_TagLib::TagLib::Tag(),
d(new TagPrivate())
{
ID3v2::Tag::Tag() : Strawberry_TagLib::TagLib::Tag(),
d(new TagPrivate()) {
d->factory = FrameFactory::instance();
}
ID3v2::Tag::Tag(File *file, long tagOffset, const FrameFactory *factory) :
Strawberry_TagLib::TagLib::Tag(),
d(new TagPrivate())
{
ID3v2::Tag::Tag(File *file, long tagOffset, const FrameFactory *factory) : Strawberry_TagLib::TagLib::Tag(),
d(new TagPrivate()) {
d->factory = factory;
d->file = file;
d->tagOffset = tagOffset;
@@ -127,59 +115,51 @@ ID3v2::Tag::Tag(File *file, long tagOffset, const FrameFactory *factory) :
read();
}
ID3v2::Tag::~Tag()
{
ID3v2::Tag::~Tag() {
delete d;
}
String ID3v2::Tag::title() const
{
if(!d->frameListMap["TIT2"].isEmpty())
String ID3v2::Tag::title() const {
if (!d->frameListMap["TIT2"].isEmpty())
return d->frameListMap["TIT2"].front()->toString();
return String();
}
String ID3v2::Tag::artist() const
{
if(!d->frameListMap["TPE1"].isEmpty())
String ID3v2::Tag::artist() const {
if (!d->frameListMap["TPE1"].isEmpty())
return d->frameListMap["TPE1"].front()->toString();
return String();
}
String ID3v2::Tag::album() const
{
if(!d->frameListMap["TALB"].isEmpty())
String ID3v2::Tag::album() const {
if (!d->frameListMap["TALB"].isEmpty())
return d->frameListMap["TALB"].front()->toString();
return String();
}
String ID3v2::Tag::comment() const
{
String ID3v2::Tag::comment() const {
const FrameList &comments = d->frameListMap["COMM"];
if(comments.isEmpty())
if (comments.isEmpty())
return String();
for(FrameList::ConstIterator it = comments.begin(); it != comments.end(); ++it)
{
for (FrameList::ConstIterator it = comments.begin(); it != comments.end(); ++it) {
CommentsFrame *frame = dynamic_cast<CommentsFrame *>(*it);
if(frame && frame->description().isEmpty())
if (frame && frame->description().isEmpty())
return (*it)->toString();
}
return comments.front()->toString();
}
String ID3v2::Tag::genre() const
{
String ID3v2::Tag::genre() const {
// TODO: In the next major version (TagLib 2.0) a list of multiple genres
// 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())) {
return String();
}
@@ -196,61 +176,55 @@ String ID3v2::Tag::genre() const
StringList genres;
for(StringList::Iterator it = fields.begin(); it != fields.end(); ++it) {
for (StringList::Iterator it = fields.begin(); it != fields.end(); ++it) {
if((*it).isEmpty())
if ((*it).isEmpty())
continue;
bool ok;
int number = (*it).toInt(&ok);
if(ok && number >= 0 && number <= 255) {
if (ok && number >= 0 && number <= 255) {
*it = ID3v1::genre(number);
}
if(std::find(genres.begin(), genres.end(), *it) == genres.end())
if (std::find(genres.begin(), genres.end(), *it) == genres.end())
genres.append(*it);
}
return genres.toString();
}
unsigned int ID3v2::Tag::year() const
{
if(!d->frameListMap["TDRC"].isEmpty())
unsigned int ID3v2::Tag::year() const {
if (!d->frameListMap["TDRC"].isEmpty())
return d->frameListMap["TDRC"].front()->toString().substr(0, 4).toInt();
return 0;
}
unsigned int ID3v2::Tag::track() const
{
if(!d->frameListMap["TRCK"].isEmpty())
unsigned int ID3v2::Tag::track() const {
if (!d->frameListMap["TRCK"].isEmpty())
return d->frameListMap["TRCK"].front()->toString().toInt();
return 0;
}
void ID3v2::Tag::setTitle(const String &s)
{
void ID3v2::Tag::setTitle(const String &s) {
setTextFrame("TIT2", s);
}
void ID3v2::Tag::setArtist(const String &s)
{
void ID3v2::Tag::setArtist(const String &s) {
setTextFrame("TPE1", s);
}
void ID3v2::Tag::setAlbum(const String &s)
{
void ID3v2::Tag::setAlbum(const String &s) {
setTextFrame("TALB", s);
}
void ID3v2::Tag::setComment(const String &s)
{
if(s.isEmpty()) {
void ID3v2::Tag::setComment(const String &s) {
if (s.isEmpty()) {
removeFrames("COMM");
return;
}
if(!d->frameListMap["COMM"].isEmpty())
if (!d->frameListMap["COMM"].isEmpty())
d->frameListMap["COMM"].front()->setText(s);
else {
CommentsFrame *f = new CommentsFrame(d->factory->defaultTextEncoding());
@@ -259,9 +233,8 @@ void ID3v2::Tag::setComment(const String &s)
}
}
void ID3v2::Tag::setGenre(const String &s)
{
if(s.isEmpty()) {
void ID3v2::Tag::setGenre(const String &s) {
if (s.isEmpty()) {
removeFrames("TCON");
return;
}
@@ -273,7 +246,7 @@ void ID3v2::Tag::setGenre(const String &s)
int index = ID3v1::genreIndex(s);
if(index != 255)
if (index != 255)
setTextFrame("TCON", String::number(index));
else
setTextFrame("TCON", s);
@@ -285,67 +258,56 @@ void ID3v2::Tag::setGenre(const String &s)
#endif
}
void ID3v2::Tag::setYear(unsigned int i)
{
if(i == 0) {
void ID3v2::Tag::setYear(unsigned int i) {
if (i == 0) {
removeFrames("TDRC");
return;
}
setTextFrame("TDRC", String::number(i));
}
void ID3v2::Tag::setTrack(unsigned int i)
{
if(i == 0) {
void ID3v2::Tag::setTrack(unsigned int i) {
if (i == 0) {
removeFrames("TRCK");
return;
}
setTextFrame("TRCK", String::number(i));
}
bool ID3v2::Tag::isEmpty() const
{
bool ID3v2::Tag::isEmpty() const {
return d->frameList.isEmpty();
}
Header *ID3v2::Tag::header() const
{
Header *ID3v2::Tag::header() const {
return &(d->header);
}
ExtendedHeader *ID3v2::Tag::extendedHeader() const
{
ExtendedHeader *ID3v2::Tag::extendedHeader() const {
return d->extendedHeader;
}
Footer *ID3v2::Tag::footer() const
{
Footer *ID3v2::Tag::footer() const {
return d->footer;
}
const FrameListMap &ID3v2::Tag::frameListMap() const
{
const FrameListMap &ID3v2::Tag::frameListMap() const {
return d->frameListMap;
}
const FrameList &ID3v2::Tag::frameList() const
{
const FrameList &ID3v2::Tag::frameList() const {
return d->frameList;
}
const FrameList &ID3v2::Tag::frameList(const ByteVector &frameID) const
{
const FrameList &ID3v2::Tag::frameList(const ByteVector &frameID) const {
return d->frameListMap[frameID];
}
void ID3v2::Tag::addFrame(Frame *frame)
{
void ID3v2::Tag::addFrame(Frame *frame) {
d->frameList.append(frame);
d->frameListMap[frame->frameID()].append(frame);
}
void ID3v2::Tag::removeFrame(Frame *frame, bool del)
{
void ID3v2::Tag::removeFrame(Frame *frame, bool del) {
// remove the frame from the frame list
FrameList::Iterator it = d->frameList.find(frame);
d->frameList.erase(it);
@@ -355,69 +317,65 @@ void ID3v2::Tag::removeFrame(Frame *frame, bool del)
d->frameListMap[frame->frameID()].erase(it);
// ...and delete as desired
if(del)
if (del)
delete frame;
}
void ID3v2::Tag::removeFrames(const ByteVector &id)
{
void ID3v2::Tag::removeFrames(const ByteVector &id) {
FrameList l = d->frameListMap[id];
for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
for (FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
removeFrame(*it, true);
}
PropertyMap ID3v2::Tag::properties() const
{
PropertyMap ID3v2::Tag::properties() const {
PropertyMap properties;
for(FrameList::ConstIterator it = frameList().begin(); it != frameList().end(); ++it) {
for (FrameList::ConstIterator it = frameList().begin(); it != frameList().end(); ++it) {
PropertyMap props = (*it)->asProperties();
properties.merge(props);
}
return properties;
}
void ID3v2::Tag::removeUnsupportedProperties(const StringList &properties)
{
for(StringList::ConstIterator it = properties.begin(); it != properties.end(); ++it){
if(it->startsWith("UNKNOWN/")) {
void ID3v2::Tag::removeUnsupportedProperties(const StringList &properties) {
for (StringList::ConstIterator it = properties.begin(); it != properties.end(); ++it) {
if (it->startsWith("UNKNOWN/")) {
String frameID = it->substr(String("UNKNOWN/").size());
if(frameID.size() != 4)
continue; // invalid specification
if (frameID.size() != 4)
continue; // invalid specification
ByteVector id = frameID.data(String::Latin1);
// delete all unknown frames of given type
FrameList l = frameList(id);
for(FrameList::ConstIterator fit = l.begin(); fit != l.end(); fit++)
for (FrameList::ConstIterator fit = l.begin(); fit != l.end(); fit++)
if (dynamic_cast<const UnknownFrame *>(*fit) != 0)
removeFrame(*fit);
}
else if(it->size() == 4){
else if (it->size() == 4) {
ByteVector id = it->data(String::Latin1);
removeFrames(id);
}
else {
ByteVector id = it->substr(0,4).data(String::Latin1);
if(it->size() <= 5)
continue; // invalid specification
ByteVector id = it->substr(0, 4).data(String::Latin1);
if (it->size() <= 5)
continue; // invalid specification
String description = it->substr(5);
Frame *frame = 0;
if(id == "TXXX")
if (id == "TXXX")
frame = UserTextIdentificationFrame::find(this, description);
else if(id == "WXXX")
else if (id == "WXXX")
frame = UserUrlLinkFrame::find(this, description);
else if(id == "COMM")
else if (id == "COMM")
frame = CommentsFrame::findByDescription(this, description);
else if(id == "USLT")
else if (id == "USLT")
frame = UnsynchronizedLyricsFrame::findByDescription(this, description);
else if(id == "UFID")
else if (id == "UFID")
frame = UniqueFileIdentifierFrame::findByOwner(this, description);
if(frame)
if (frame)
removeFrame(frame);
}
}
}
PropertyMap ID3v2::Tag::setProperties(const PropertyMap &origProps)
{
PropertyMap ID3v2::Tag::setProperties(const PropertyMap &origProps) {
FrameList framesToDelete;
// we split up the PropertyMap into the "normal" keys and the "complicated" ones,
// which are those according to TIPL or TMCL frames.
@@ -425,48 +383,48 @@ PropertyMap ID3v2::Tag::setProperties(const PropertyMap &origProps)
PropertyMap tiplProperties;
PropertyMap tmclProperties;
Frame::splitProperties(origProps, properties, tiplProperties, tmclProperties);
for(FrameListMap::ConstIterator it = frameListMap().begin(); it != frameListMap().end(); ++it){
for(FrameList::ConstIterator lit = it->second.begin(); lit != it->second.end(); ++lit){
for (FrameListMap::ConstIterator it = frameListMap().begin(); it != frameListMap().end(); ++it) {
for (FrameList::ConstIterator lit = it->second.begin(); lit != it->second.end(); ++lit) {
PropertyMap frameProperties = (*lit)->asProperties();
if(it->first == "TIPL") {
if (it->first == "TIPL") {
if (tiplProperties != frameProperties)
framesToDelete.append(*lit);
else
tiplProperties.erase(frameProperties);
} else if(it->first == "TMCL") {
}
else if (it->first == "TMCL") {
if (tmclProperties != frameProperties)
framesToDelete.append(*lit);
else
tmclProperties.erase(frameProperties);
} else if(!properties.contains(frameProperties))
}
else if (!properties.contains(frameProperties))
framesToDelete.append(*lit);
else
properties.erase(frameProperties);
}
}
for(FrameList::ConstIterator it = framesToDelete.begin(); it != framesToDelete.end(); ++it)
for (FrameList::ConstIterator it = framesToDelete.begin(); it != framesToDelete.end(); ++it)
removeFrame(*it);
// now create remaining frames:
// start with the involved people list (TIPL)
if(!tiplProperties.isEmpty())
addFrame(TextIdentificationFrame::createTIPLFrame(tiplProperties));
if (!tiplProperties.isEmpty())
addFrame(TextIdentificationFrame::createTIPLFrame(tiplProperties));
// proceed with the musician credit list (TMCL)
if(!tmclProperties.isEmpty())
addFrame(TextIdentificationFrame::createTMCLFrame(tmclProperties));
if (!tmclProperties.isEmpty())
addFrame(TextIdentificationFrame::createTMCLFrame(tmclProperties));
// now create the "one key per frame" frames
for(PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it)
for (PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it)
addFrame(Frame::createTextualFrame(it->first, it->second));
return PropertyMap(); // ID3 implements the complete PropertyMap interface, so an empty map is returned
return PropertyMap(); // ID3 implements the complete PropertyMap interface, so an empty map is returned
}
ByteVector ID3v2::Tag::render() const
{
ByteVector ID3v2::Tag::render() const {
return render(ID3v2::v4);
}
void ID3v2::Tag::downgradeFrames(FrameList *frames, FrameList *newFrames) const
{
void ID3v2::Tag::downgradeFrames(FrameList *frames, FrameList *newFrames) const {
#ifdef NO_ITUNES_HACKS
const char *unsupportedFrames[] = {
"ASPI", "EQU2", "RVA2", "SEEK", "SIGN", "TDRL", "TDTG",
@@ -483,59 +441,58 @@ void ID3v2::Tag::downgradeFrames(FrameList *frames, FrameList *newFrames) const
ID3v2::TextIdentificationFrame *frameTDRC = 0;
ID3v2::TextIdentificationFrame *frameTIPL = 0;
ID3v2::TextIdentificationFrame *frameTMCL = 0;
for(FrameList::ConstIterator it = d->frameList.begin(); it != d->frameList.end(); it++) {
for (FrameList::ConstIterator it = d->frameList.begin(); it != d->frameList.end(); it++) {
ID3v2::Frame *frame = *it;
ByteVector frameID = frame->header()->frameID();
for(int i = 0; unsupportedFrames[i]; i++) {
if(frameID == unsupportedFrames[i]) {
debug("A frame that is not supported in ID3v2.3 \'"
+ String(frameID) + "\' has been discarded");
for (int i = 0; unsupportedFrames[i]; i++) {
if (frameID == unsupportedFrames[i]) {
debug("A frame that is not supported in ID3v2.3 \'" + String(frameID) + "\' has been discarded");
frame = 0;
break;
}
}
if(frame && frameID == "TDOR") {
if (frame && frameID == "TDOR") {
frameTDOR = dynamic_cast<ID3v2::TextIdentificationFrame *>(frame);
frame = 0;
}
if(frame && frameID == "TDRC") {
if (frame && frameID == "TDRC") {
frameTDRC = dynamic_cast<ID3v2::TextIdentificationFrame *>(frame);
frame = 0;
}
if(frame && frameID == "TIPL") {
if (frame && frameID == "TIPL") {
frameTIPL = dynamic_cast<ID3v2::TextIdentificationFrame *>(frame);
frame = 0;
}
if(frame && frameID == "TMCL") {
if (frame && frameID == "TMCL") {
frameTMCL = dynamic_cast<ID3v2::TextIdentificationFrame *>(frame);
frame = 0;
}
if(frame) {
if (frame) {
frames->append(frame);
}
}
if(frameTDOR) {
if (frameTDOR) {
String content = frameTDOR->toString();
if(content.size() >= 4) {
if (content.size() >= 4) {
ID3v2::TextIdentificationFrame *frameTORY = new ID3v2::TextIdentificationFrame("TORY", String::Latin1);
frameTORY->setText(content.substr(0, 4));
frames->append(frameTORY);
newFrames->append(frameTORY);
}
}
if(frameTDRC) {
if (frameTDRC) {
String content = frameTDRC->toString();
if(content.size() >= 4) {
if (content.size() >= 4) {
ID3v2::TextIdentificationFrame *frameTYER = new ID3v2::TextIdentificationFrame("TYER", String::Latin1);
frameTYER->setText(content.substr(0, 4));
frames->append(frameTYER);
newFrames->append(frameTYER);
if(content.size() >= 10 && content[4] == '-' && content[7] == '-') {
if (content.size() >= 10 && content[4] == '-' && content[7] == '-') {
ID3v2::TextIdentificationFrame *frameTDAT = new ID3v2::TextIdentificationFrame("TDAT", String::Latin1);
frameTDAT->setText(content.substr(8, 2) + content.substr(5, 2));
frames->append(frameTDAT);
newFrames->append(frameTDAT);
if(content.size() >= 16 && content[10] == 'T' && content[13] == ':') {
if (content.size() >= 16 && content[10] == 'T' && content[13] == ':') {
ID3v2::TextIdentificationFrame *frameTIME = new ID3v2::TextIdentificationFrame("TIME", String::Latin1);
frameTIME->setText(content.substr(11, 2) + content.substr(14, 2));
frames->append(frameTIME);
@@ -544,21 +501,21 @@ void ID3v2::Tag::downgradeFrames(FrameList *frames, FrameList *newFrames) const
}
}
}
if(frameTIPL || frameTMCL) {
if (frameTIPL || frameTMCL) {
ID3v2::TextIdentificationFrame *frameIPLS = new ID3v2::TextIdentificationFrame("IPLS", String::Latin1);
StringList people;
if(frameTMCL) {
if (frameTMCL) {
StringList v24People = frameTMCL->fieldList();
for(unsigned int i = 0; i + 1 < v24People.size(); i += 2) {
for (unsigned int i = 0; i + 1 < v24People.size(); i += 2) {
people.append(v24People[i]);
people.append(v24People[i+1]);
people.append(v24People[i + 1]);
}
}
if(frameTIPL) {
if (frameTIPL) {
StringList v24People = frameTIPL->fieldList();
for(unsigned int i = 0; i + 1 < v24People.size(); i += 2) {
for (unsigned int i = 0; i + 1 < v24People.size(); i += 2) {
people.append(v24People[i]);
people.append(v24People[i+1]);
people.append(v24People[i + 1]);
}
}
frameIPLS->setText(people);
@@ -567,13 +524,11 @@ void ID3v2::Tag::downgradeFrames(FrameList *frames, FrameList *newFrames) const
}
}
ByteVector ID3v2::Tag::render(int version) const
{
ByteVector ID3v2::Tag::render(int version) const {
return render(version == 3 ? v3 : v4);
}
ByteVector ID3v2::Tag::render(Version version) const
{
ByteVector ID3v2::Tag::render(Version version) const {
// We need to render the "tag data" first so that we have to correct size to
// render in the tag's header. The "tag data" -- everything that is included
// in ID3v2::Header::tagSize() -- includes the extended header, frames and
@@ -587,7 +542,7 @@ ByteVector ID3v2::Tag::render(Version version) const
newFrames.setAutoDelete(true);
FrameList frameList;
if(version == v4) {
if (version == v4) {
frameList = d->frameList;
}
else {
@@ -600,18 +555,16 @@ ByteVector ID3v2::Tag::render(Version version) const
// Loop through the frames rendering them and adding them to the tagData.
for(FrameList::ConstIterator it = frameList.begin(); it != frameList.end(); it++) {
for (FrameList::ConstIterator it = frameList.begin(); it != frameList.end(); it++) {
(*it)->header()->setVersion(version == v3 ? 3 : 4);
if((*it)->header()->frameID().size() != 4) {
debug("An ID3v2 frame of unsupported or unknown type \'"
+ String((*it)->header()->frameID()) + "\' has been discarded");
if ((*it)->header()->frameID().size() != 4) {
debug("An ID3v2 frame of unsupported or unknown type \'" + String((*it)->header()->frameID()) + "\' has been discarded");
continue;
}
if(!(*it)->header()->tagAlterPreservation()) {
if (!(*it)->header()->tagAlterPreservation()) {
const ByteVector frameData = (*it)->render();
if(frameData.size() == Frame::headerSize((*it)->header()->version())) {
debug("An empty ID3v2 frame \'"
+ String((*it)->header()->frameID()) + "\' has been discarded");
if (frameData.size() == Frame::headerSize((*it)->header()->version())) {
debug("An empty ID3v2 frame \'" + String((*it)->header()->frameID()) + "\' has been discarded");
continue;
}
tagData.append(frameData);
@@ -623,7 +576,7 @@ ByteVector ID3v2::Tag::render(Version version) const
long originalSize = d->header.tagSize();
long paddingSize = originalSize - (tagData.size() - Header::size());
if(paddingSize <= 0) {
if (paddingSize <= 0) {
paddingSize = MinPaddingSize;
}
else {
@@ -633,7 +586,7 @@ ByteVector ID3v2::Tag::render(Version version) const
threshold = std::max(threshold, MinPaddingSize);
threshold = std::min(threshold, MaxPaddingSize);
if(paddingSize > threshold)
if (paddingSize > threshold)
paddingSize = MinPaddingSize;
}
@@ -650,14 +603,12 @@ ByteVector ID3v2::Tag::render(Version version) const
return tagData;
}
Latin1StringHandler const *ID3v2::Tag::latin1StringHandler()
{
Latin1StringHandler const *ID3v2::Tag::latin1StringHandler() {
return stringHandler;
}
void ID3v2::Tag::setLatin1StringHandler(const Latin1StringHandler *handler)
{
if(handler)
void ID3v2::Tag::setLatin1StringHandler(const Latin1StringHandler *handler) {
if (handler)
stringHandler = handler;
else
stringHandler = &defaultStringHandler;
@@ -667,12 +618,11 @@ void ID3v2::Tag::setLatin1StringHandler(const Latin1StringHandler *handler)
// protected members
////////////////////////////////////////////////////////////////////////////////
void ID3v2::Tag::read()
{
if(!d->file)
void ID3v2::Tag::read() {
if (!d->file)
return;
if(!d->file->isOpen())
if (!d->file->isOpen())
return;
d->file->seek(d->tagOffset);
@@ -681,7 +631,7 @@ void ID3v2::Tag::read()
// If the tag size is 0, then this is an invalid tag (tags must contain at
// least one frame)
if(d->header.tagSize() != 0)
if (d->header.tagSize() != 0)
parse(d->file->readBlock(d->header.tagSize()));
// Look for duplicate ID3v2 tags and treat them as an extra blank of this one.
@@ -692,28 +642,27 @@ void ID3v2::Tag::read()
unsigned int extraSize = 0;
while(true) {
while (true) {
d->file->seek(d->tagOffset + d->header.completeTagSize() + extraSize);
const ByteVector data = d->file->readBlock(Header::size());
if(data.size() < Header::size() || !data.startsWith(Header::fileIdentifier()))
if (data.size() < Header::size() || !data.startsWith(Header::fileIdentifier()))
break;
extraSize += Header(data).completeTagSize();
}
if(extraSize != 0) {
if (extraSize != 0) {
debug("ID3v2::Tag::read() - Duplicate ID3v2 tags found.");
d->header.setTagSize(d->header.tagSize() + extraSize);
}
}
void ID3v2::Tag::parse(const ByteVector &origData)
{
void ID3v2::Tag::parse(const ByteVector &origData) {
ByteVector data = origData;
if(d->header.unsynchronisation() && d->header.majorVersion() <= 3)
if (d->header.unsynchronisation() && d->header.majorVersion() <= 3)
data = SynchData::decode(data);
unsigned int frameDataPosition = 0;
@@ -721,11 +670,11 @@ void ID3v2::Tag::parse(const ByteVector &origData)
// check for extended header
if(d->header.extendedHeader()) {
if(!d->extendedHeader)
if (d->header.extendedHeader()) {
if (!d->extendedHeader)
d->extendedHeader = new ExtendedHeader();
d->extendedHeader->setData(data);
if(d->extendedHeader->size() <= data.size()) {
if (d->extendedHeader->size() <= data.size()) {
frameDataPosition += d->extendedHeader->size();
frameDataLength -= d->extendedHeader->size();
}
@@ -735,7 +684,7 @@ void ID3v2::Tag::parse(const ByteVector &origData)
// contain the same data as the header, but we do need to account for its
// size.
if(d->header.footerPresent() && Footer::size() <= frameDataLength)
if (d->header.footerPresent() && Footer::size() <= frameDataLength)
frameDataLength -= Footer::size();
// parse frames
@@ -743,13 +692,13 @@ void ID3v2::Tag::parse(const ByteVector &origData)
// Make sure that there is at least enough room in the remaining frame data for
// a frame header.
while(frameDataPosition < frameDataLength - Frame::headerSize(d->header.majorVersion())) {
while (frameDataPosition < frameDataLength - Frame::headerSize(d->header.majorVersion())) {
// If the next data is position is 0, assume that we've hit the padding
// portion of the frame data.
if(data.at(frameDataPosition) == 0) {
if(d->header.footerPresent()) {
if (data.at(frameDataPosition) == 0) {
if (d->header.footerPresent()) {
debug("Padding *and* a footer found. This is not allowed by the spec.");
}
@@ -757,14 +706,14 @@ void ID3v2::Tag::parse(const ByteVector &origData)
}
Frame *frame = d->factory->createFrame(data.mid(frameDataPosition),
&d->header);
&d->header);
if(!frame)
if (!frame)
return;
// Checks to make sure that frame parsed correctly.
if(frame->size() <= 0) {
if (frame->size() <= 0) {
delete frame;
return;
}
@@ -776,14 +725,13 @@ void ID3v2::Tag::parse(const ByteVector &origData)
d->factory->rebuildAggregateFrames(this);
}
void ID3v2::Tag::setTextFrame(const ByteVector &id, const String &value)
{
if(value.isEmpty()) {
void ID3v2::Tag::setTextFrame(const ByteVector &id, const String &value) {
if (value.isEmpty()) {
removeFrames(id);
return;
}
if(!d->frameListMap[id].isEmpty())
if (!d->frameListMap[id].isEmpty())
d->frameListMap[id].front()->setText(value);
else {
const String::Type encoding = d->factory->defaultTextEncoding();

View File

@@ -39,20 +39,20 @@
namespace Strawberry_TagLib {
namespace TagLib {
class File;
class File;
namespace ID3v2 {
namespace ID3v2 {
class Header;
class ExtendedHeader;
class Footer;
class Header;
class ExtendedHeader;
class Footer;
typedef List<Frame *> FrameList;
typedef Map<ByteVector, FrameList> FrameListMap;
typedef List<Frame *> FrameList;
typedef Map<ByteVector, FrameList> FrameListMap;
//! An abstraction for the ISO-8859-1 string to data encoding in ID3v2 tags.
//! An abstraction for the ISO-8859-1 string to data encoding in ID3v2 tags.
/*!
/*!
* ID3v2 tag can store strings in ISO-8859-1 (Latin1), and TagLib only
* supports genuine ISO-8859-1 by default. However, in practice, non
* ISO-8859-1 encodings are often used instead of ISO-8859-1, such as
@@ -67,22 +67,21 @@ namespace TagLib {
*
* \see ID3v2::Tag::setStringHandler()
*/
class TAGLIB_EXPORT Latin1StringHandler
{
public:
Latin1StringHandler();
virtual ~Latin1StringHandler();
class TAGLIB_EXPORT Latin1StringHandler {
public:
Latin1StringHandler();
virtual ~Latin1StringHandler();
/*!
/*!
* Decode a string from \a data. The default implementation assumes that
* \a data is an ISO-8859-1 (Latin1) character array.
*/
virtual String parse(const ByteVector &data) const;
};
virtual String parse(const ByteVector &data) const;
};
//! The main class in the ID3v2 implementation
//! The main class in the ID3v2 implementation
/*!
/*!
* This is the main class in the ID3v2 implementation. It serves two
* functions. This first, as is obvious from the public API, is to provide a
* container for the other ID3v2 related classes. In addition, through the
@@ -125,17 +124,16 @@ namespace TagLib {
* working knowledge of ID3v2 structure. You're been warned.
*/
class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag
{
public:
/*!
class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
public:
/*!
* Constructs an empty ID3v2 tag.
*
* \note You must create at least one frame for this tag to be valid.
*/
Tag();
Tag();
/*!
/*!
* Constructs an ID3v2 tag read from \a file starting at \a tagOffset.
* \a factory specifies which FrameFactory will be used for the
* construction of new frames.
@@ -147,46 +145,46 @@ namespace TagLib {
*
* \see FrameFactory
*/
Tag(File *file, long tagOffset,
const FrameFactory *factory = FrameFactory::instance());
Tag(File *file, long tagOffset,
const FrameFactory *factory = FrameFactory::instance());
/*!
/*!
* Destroys this Tag instance.
*/
virtual ~Tag();
virtual ~Tag();
// Reimplementations.
// Reimplementations.
virtual String title() const;
virtual String artist() const;
virtual String album() const;
virtual String comment() const;
virtual String genre() const;
virtual unsigned int year() const;
virtual unsigned int track() const;
virtual String title() const;
virtual String artist() const;
virtual String album() const;
virtual String comment() const;
virtual String genre() const;
virtual unsigned int year() const;
virtual unsigned int track() const;
virtual void setTitle(const String &s);
virtual void setArtist(const String &s);
virtual void setAlbum(const String &s);
virtual void setComment(const String &s);
virtual void setGenre(const String &s);
virtual void setYear(unsigned int i);
virtual void setTrack(unsigned int i);
virtual void setTitle(const String &s);
virtual void setArtist(const String &s);
virtual void setAlbum(const String &s);
virtual void setComment(const String &s);
virtual void setGenre(const String &s);
virtual void setYear(unsigned int i);
virtual void setTrack(unsigned int i);
virtual bool isEmpty() const;
virtual bool isEmpty() const;
/*!
/*!
* Returns a pointer to the tag's header.
*/
Header *header() const;
Header *header() const;
/*!
/*!
* Returns a pointer to the tag's extended header or null if there is no
* extended header.
*/
ExtendedHeader *extendedHeader() const;
ExtendedHeader *extendedHeader() const;
/*!
/*!
* Returns a pointer to the tag's footer or null if there is no footer.
*
* \deprecated I don't see any reason to keep this around since there's
@@ -194,9 +192,9 @@ namespace TagLib {
* prone to change my mind, so this gets to stay around until near a
* release.
*/
TAGLIB_DEPRECATED Footer *footer() const;
TAGLIB_DEPRECATED Footer *footer() const;
/*!
/*!
* Returns a reference to the frame list map. This is an FrameListMap of
* all of the frames in the tag.
*
@@ -230,9 +228,9 @@ namespace TagLib {
*
* \see frameList()
*/
const FrameListMap &frameListMap() const;
const FrameListMap &frameListMap() const;
/*!
/*!
* Returns a reference to the frame list. This is an FrameList of all of
* the frames in the tag in the order that they were parsed.
*
@@ -242,9 +240,9 @@ namespace TagLib {
* \warning You should not modify this data structure directly, instead
* use addFrame() and removeFrame().
*/
const FrameList &frameList() const;
const FrameList &frameList() const;
/*!
/*!
* Returns the frame list for frames with the id \a frameID or an empty
* list if there are no frames of that type. This is just a convenience
* and is equivalent to:
@@ -255,35 +253,35 @@ namespace TagLib {
*
* \see frameListMap()
*/
const FrameList &frameList(const ByteVector &frameID) const;
const FrameList &frameList(const ByteVector &frameID) const;
/*!
/*!
* Add a frame to the tag. At this point the tag takes ownership of
* the frame and will handle freeing its memory.
*
* \note Using this method will invalidate any pointers on the list
* returned by frameList()
*/
void addFrame(Frame *frame);
void addFrame(Frame *frame);
/*!
/*!
* Remove a frame from the tag. If \a del is true the frame's memory
* will be freed; if it is false, it must be deleted by the user.
*
* \note Using this method will invalidate any pointers on the list
* returned by frameList()
*/
void removeFrame(Frame *frame, bool del = true);
void removeFrame(Frame *frame, bool del = true);
/*!
/*!
* Remove all frames of type \a id from the tag and free their memory.
*
* \note Using this method will invalidate any pointers on the list
* returned by frameList()
*/
void removeFrames(const ByteVector &id);
void removeFrames(const ByteVector &id);
/*!
/*!
* Implements the unified property interface -- export function.
* This function does some work to translate the hard-specified ID3v2
* frame types into a free-form string-to-stringlist PropertyMap:
@@ -312,9 +310,9 @@ namespace TagLib {
* once, the description, separated by a "/".
*
*/
PropertyMap properties() const;
PropertyMap properties() const;
/*!
/*!
* Removes unsupported frames given by \a properties. The elements of
* \a properties must be taken from properties().unsupportedData(); they
* are of one of the following forms:
@@ -325,41 +323,41 @@ namespace TagLib {
* - "UNKNOWN/" + frameID, for frames that could not be parsed by TagLib.
* In that case, *all* unknown frames with the given ID will be removed.
*/
void removeUnsupportedProperties(const StringList &properties);
void removeUnsupportedProperties(const StringList &properties);
/*!
/*!
* Implements the unified property interface -- import function.
* See the comments in properties().
*/
PropertyMap setProperties(const PropertyMap &);
PropertyMap setProperties(const PropertyMap &);
/*!
/*!
* Render the tag back to binary data, suitable to be written to disk.
*/
ByteVector render() const;
ByteVector render() const;
/*!
/*!
* \deprecated
*/
TAGLIB_DEPRECATED ByteVector render(int version) const;
TAGLIB_DEPRECATED ByteVector render(int version) const;
/*!
/*!
* Render the tag back to binary data, suitable to be written to disk.
*
* The \a version parameter specifies whether ID3v2.4 (default) or ID3v2.3
* should be used.
*/
ByteVector render(Version version) const;
ByteVector render(Version version) const;
/*!
/*!
* Gets the current string handler that decides how the "Latin-1" data
* will be converted to and from binary data.
*
* \see Latin1StringHandler
*/
static Latin1StringHandler const *latin1StringHandler();
static Latin1StringHandler const *latin1StringHandler();
/*!
/*!
* Sets the string handler that decides how the "Latin-1" data will be
* converted to and from binary data.
* If the parameter \a handler is null, the previous handler is
@@ -370,44 +368,44 @@ namespace TagLib {
*
* \see Latin1StringHandler
*/
static void setLatin1StringHandler(const Latin1StringHandler *handler);
static void setLatin1StringHandler(const Latin1StringHandler *handler);
protected:
/*!
protected:
/*!
* Reads data from the file specified in the constructor. It does basic
* parsing of the data in the largest chunks. It partitions the tag into
* the Header, the body of the tag (which contains the ExtendedHeader and
* frames) and Footer.
*/
void read();
void read();
/*!
/*!
* This is called by read to parse the body of the tag. It determines if an
* extended header exists and adds frames to the FrameListMap.
*/
void parse(const ByteVector &data);
void parse(const ByteVector &data);
/*!
/*!
* Sets the value of the text frame with the Frame ID \a id to \a value.
* If the frame does not exist, it is created.
*/
void setTextFrame(const ByteVector &id, const String &value);
void setTextFrame(const ByteVector &id, const String &value);
/*!
/*!
* Dowgrade frames from ID3v2.4 (used internally and by default) to ID3v2.3
*/
void downgradeFrames(FrameList *existingFrames, FrameList *newFrames) const;
void downgradeFrames(FrameList *existingFrames, FrameList *newFrames) const;
private:
Tag(const Tag &);
Tag &operator=(const Tag &);
private:
Tag(const Tag &);
Tag &operator=(const Tag &);
class TagPrivate;
TagPrivate *d;
};
class TagPrivate;
TagPrivate *d;
};
}
}
}
} // namespace ID3v2
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -39,25 +39,23 @@
using namespace Strawberry_TagLib::TagLib;
namespace
{
enum { ID3v2Index = 0, APEIndex = 1, ID3v1Index = 2 };
namespace {
enum { ID3v2Index = 0,
APEIndex = 1,
ID3v1Index = 2 };
}
class MPEG::File::FilePrivate
{
public:
explicit FilePrivate(const ID3v2::FrameFactory *frameFactory = ID3v2::FrameFactory::instance()) :
ID3v2FrameFactory(frameFactory),
ID3v2Location(-1),
ID3v2OriginalSize(0),
APELocation(-1),
APEOriginalSize(0),
ID3v1Location(-1),
properties(0) {}
class MPEG::File::FilePrivate {
public:
explicit FilePrivate(const ID3v2::FrameFactory *frameFactory = ID3v2::FrameFactory::instance()) : ID3v2FrameFactory(frameFactory),
ID3v2Location(-1),
ID3v2OriginalSize(0),
APELocation(-1),
APEOriginalSize(0),
ID3v1Location(-1),
properties(0) {}
~FilePrivate()
{
~FilePrivate() {
delete properties;
}
@@ -80,24 +78,21 @@ public:
// static members
////////////////////////////////////////////////////////////////////////////////
namespace
{
// Dummy file class to make a stream work with MPEG::Header.
namespace {
// Dummy file class to make a stream work with MPEG::Header.
class AdapterFile : public Strawberry_TagLib::TagLib::File
{
public:
explicit AdapterFile(IOStream *stream) : File(stream) {}
class AdapterFile : public Strawberry_TagLib::TagLib::File {
public:
explicit AdapterFile(IOStream *stream) : File(stream) {}
Tag *tag() const { return nullptr; }
AudioProperties *audioProperties() const { return nullptr; }
bool save() { return false; }
};
}
Tag *tag() const { return nullptr; }
AudioProperties *audioProperties() const { return nullptr; }
bool save() { return false; }
};
} // namespace
bool MPEG::File::isSupported(IOStream *stream)
{
if(!stream || !stream->isOpen())
bool MPEG::File::isSupported(IOStream *stream) {
if (!stream || !stream->isOpen())
return false;
// An MPEG file has MPEG frame headers. An ID3v2 tag may precede.
@@ -108,16 +103,16 @@ bool MPEG::File::isSupported(IOStream *stream)
long headerOffset;
const ByteVector buffer = Utils::readHeader(stream, bufferSize(), true, &headerOffset);
if(buffer.isEmpty())
if (buffer.isEmpty())
return false;
const long originalPosition = stream->tell();
AdapterFile file(stream);
for(unsigned int i = 0; i < buffer.size() - 1; ++i) {
if(isFrameSync(buffer, i)) {
for (unsigned int i = 0; i < buffer.size() - 1; ++i) {
if (isFrameSync(buffer, i)) {
const Header header(&file, headerOffset + i, true);
if(header.isValid()) {
if (header.isValid()) {
stream->seek(originalPosition);
return true;
}
@@ -132,139 +127,121 @@ bool MPEG::File::isSupported(IOStream *stream)
// public members
////////////////////////////////////////////////////////////////////////////////
MPEG::File::File(FileName file, bool readProperties, Properties::ReadStyle) :
Strawberry_TagLib::TagLib::File(file),
d(new FilePrivate())
{
if(isOpen())
MPEG::File::File(FileName file, bool readProperties, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(file),
d(new FilePrivate()) {
if (isOpen())
read(readProperties);
}
MPEG::File::File(FileName file, ID3v2::FrameFactory *frameFactory,
bool readProperties, Properties::ReadStyle) :
Strawberry_TagLib::TagLib::File(file),
d(new FilePrivate(frameFactory))
{
if(isOpen())
bool readProperties, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(file),
d(new FilePrivate(frameFactory)) {
if (isOpen())
read(readProperties);
}
MPEG::File::File(IOStream *stream, ID3v2::FrameFactory *frameFactory,
bool readProperties, Properties::ReadStyle) :
Strawberry_TagLib::TagLib::File(stream),
d(new FilePrivate(frameFactory))
{
if(isOpen())
bool readProperties, Properties::ReadStyle) : Strawberry_TagLib::TagLib::File(stream),
d(new FilePrivate(frameFactory)) {
if (isOpen())
read(readProperties);
}
MPEG::File::~File()
{
MPEG::File::~File() {
delete d;
}
Strawberry_TagLib::TagLib::Tag *MPEG::File::tag() const
{
Strawberry_TagLib::TagLib::Tag *MPEG::File::tag() const {
return &d->tag;
}
PropertyMap MPEG::File::properties() const
{
PropertyMap MPEG::File::properties() const {
return d->tag.properties();
}
void MPEG::File::removeUnsupportedProperties(const StringList &properties)
{
void MPEG::File::removeUnsupportedProperties(const StringList &properties) {
d->tag.removeUnsupportedProperties(properties);
}
PropertyMap MPEG::File::setProperties(const PropertyMap &properties)
{
PropertyMap MPEG::File::setProperties(const PropertyMap &properties) {
// update ID3v1 tag if it exists, but ignore the return value
if(ID3v1Tag())
if (ID3v1Tag())
ID3v1Tag()->setProperties(properties);
return ID3v2Tag(true)->setProperties(properties);
}
MPEG::Properties *MPEG::File::audioProperties() const
{
MPEG::Properties *MPEG::File::audioProperties() const {
return d->properties;
}
bool MPEG::File::save()
{
bool MPEG::File::save() {
return save(AllTags);
}
bool MPEG::File::save(int tags)
{
bool MPEG::File::save(int tags) {
return save(tags, StripOthers);
}
bool MPEG::File::save(int tags, bool stripOthers)
{
bool MPEG::File::save(int tags, bool stripOthers) {
return save(tags, stripOthers ? StripOthers : StripNone, ID3v2::v4);
}
bool MPEG::File::save(int tags, bool stripOthers, int id3v2Version)
{
bool MPEG::File::save(int tags, bool stripOthers, int id3v2Version) {
return save(tags,
stripOthers ? StripOthers : StripNone,
id3v2Version == 3 ? ID3v2::v3 : ID3v2::v4);
stripOthers ? StripOthers : StripNone,
id3v2Version == 3 ? ID3v2::v3 : ID3v2::v4);
}
bool MPEG::File::save(int tags, bool stripOthers, int id3v2Version, bool duplicateTags)
{
bool MPEG::File::save(int tags, bool stripOthers, int id3v2Version, bool duplicateTags) {
return save(tags,
stripOthers ? StripOthers : StripNone,
id3v2Version == 3 ? ID3v2::v3 : ID3v2::v4,
duplicateTags ? Duplicate : DoNotDuplicate);
stripOthers ? StripOthers : StripNone,
id3v2Version == 3 ? ID3v2::v3 : ID3v2::v4,
duplicateTags ? Duplicate : DoNotDuplicate);
}
bool MPEG::File::save(int tags, StripTags strip, ID3v2::Version version, DuplicateTags duplicate)
{
if(readOnly()) {
bool MPEG::File::save(int tags, StripTags strip, ID3v2::Version version, DuplicateTags duplicate) {
if (readOnly()) {
debug("MPEG::File::save() -- File is read only.");
return false;
}
// Create the tags if we've been asked to.
if(duplicate == Duplicate) {
if (duplicate == Duplicate) {
// Copy the values from the tag that does exist into the new tag,
// except if the existing tag is to be stripped.
if((tags & ID3v2) && ID3v1Tag() && !(strip == StripOthers && !(tags & ID3v1)))
if ((tags & ID3v2) && ID3v1Tag() && !(strip == StripOthers && !(tags & ID3v1)))
Tag::duplicate(ID3v1Tag(), ID3v2Tag(true), false);
if((tags & ID3v1) && d->tag[ID3v2Index] && !(strip == StripOthers && !(tags & ID3v2)))
if ((tags & ID3v1) && d->tag[ID3v2Index] && !(strip == StripOthers && !(tags & ID3v2)))
Tag::duplicate(ID3v2Tag(), ID3v1Tag(true), false);
}
// Remove all the tags not going to be saved.
if(strip == StripOthers)
if (strip == StripOthers)
File::strip(~tags, false);
if(ID3v2 & tags) {
if (ID3v2 & tags) {
if(ID3v2Tag() && !ID3v2Tag()->isEmpty()) {
if (ID3v2Tag() && !ID3v2Tag()->isEmpty()) {
// ID3v2 tag is not empty. Update the old one or create a new one.
if(d->ID3v2Location < 0)
if (d->ID3v2Location < 0)
d->ID3v2Location = 0;
const ByteVector data = ID3v2Tag()->render(version);
insert(data, d->ID3v2Location, d->ID3v2OriginalSize);
if(d->APELocation >= 0)
if (d->APELocation >= 0)
d->APELocation += (static_cast<long>(data.size()) - d->ID3v2OriginalSize);
if(d->ID3v1Location >= 0)
if (d->ID3v1Location >= 0)
d->ID3v1Location += (static_cast<long>(data.size()) - d->ID3v2OriginalSize);
d->ID3v2OriginalSize = data.size();
@@ -277,13 +254,13 @@ bool MPEG::File::save(int tags, StripTags strip, ID3v2::Version version, Duplica
}
}
if(ID3v1 & tags) {
if (ID3v1 & tags) {
if(ID3v1Tag() && !ID3v1Tag()->isEmpty()) {
if (ID3v1Tag() && !ID3v1Tag()->isEmpty()) {
// ID3v1 tag is not empty. Update the old one or create a new one.
if(d->ID3v1Location >= 0) {
if (d->ID3v1Location >= 0) {
seek(d->ID3v1Location);
}
else {
@@ -301,14 +278,14 @@ bool MPEG::File::save(int tags, StripTags strip, ID3v2::Version version, Duplica
}
}
if(APE & tags) {
if (APE & tags) {
if(APETag() && !APETag()->isEmpty()) {
if (APETag() && !APETag()->isEmpty()) {
// APE tag is not empty. Update the old one or create a new one.
if(d->APELocation < 0) {
if(d->ID3v1Location >= 0)
if (d->APELocation < 0) {
if (d->ID3v1Location >= 0)
d->APELocation = d->ID3v1Location;
else
d->APELocation = length();
@@ -317,7 +294,7 @@ bool MPEG::File::save(int tags, StripTags strip, ID3v2::Version version, Duplica
const ByteVector data = APETag()->render();
insert(data, d->APELocation, d->APEOriginalSize);
if(d->ID3v1Location >= 0)
if (d->ID3v1Location >= 0)
d->ID3v1Location += (static_cast<long>(data.size()) - d->APEOriginalSize);
d->APEOriginalSize = data.size();
@@ -333,95 +310,88 @@ bool MPEG::File::save(int tags, StripTags strip, ID3v2::Version version, Duplica
return true;
}
ID3v2::Tag *MPEG::File::ID3v2Tag(bool create)
{
ID3v2::Tag *MPEG::File::ID3v2Tag(bool create) {
return d->tag.access<ID3v2::Tag>(ID3v2Index, create);
}
ID3v1::Tag *MPEG::File::ID3v1Tag(bool create)
{
ID3v1::Tag *MPEG::File::ID3v1Tag(bool create) {
return d->tag.access<ID3v1::Tag>(ID3v1Index, create);
}
APE::Tag *MPEG::File::APETag(bool create)
{
APE::Tag *MPEG::File::APETag(bool create) {
return d->tag.access<APE::Tag>(APEIndex, create);
}
bool MPEG::File::strip(int tags)
{
bool MPEG::File::strip(int tags) {
return strip(tags, true);
}
bool MPEG::File::strip(int tags, bool freeMemory)
{
if(readOnly()) {
bool MPEG::File::strip(int tags, bool freeMemory) {
if (readOnly()) {
debug("MPEG::File::strip() - Cannot strip tags from a read only file.");
return false;
}
if((tags & ID3v2) && d->ID3v2Location >= 0) {
if ((tags & ID3v2) && d->ID3v2Location >= 0) {
removeBlock(d->ID3v2Location, d->ID3v2OriginalSize);
if(d->APELocation >= 0)
if (d->APELocation >= 0)
d->APELocation -= d->ID3v2OriginalSize;
if(d->ID3v1Location >= 0)
if (d->ID3v1Location >= 0)
d->ID3v1Location -= d->ID3v2OriginalSize;
d->ID3v2Location = -1;
d->ID3v2OriginalSize = 0;
if(freeMemory)
if (freeMemory)
d->tag.set(ID3v2Index, 0);
}
if((tags & ID3v1) && d->ID3v1Location >= 0) {
if ((tags & ID3v1) && d->ID3v1Location >= 0) {
truncate(d->ID3v1Location);
d->ID3v1Location = -1;
if(freeMemory)
if (freeMemory)
d->tag.set(ID3v1Index, 0);
}
if((tags & APE) && d->APELocation >= 0) {
if ((tags & APE) && d->APELocation >= 0) {
removeBlock(d->APELocation, d->APEOriginalSize);
if(d->ID3v1Location >= 0)
if (d->ID3v1Location >= 0)
d->ID3v1Location -= d->APEOriginalSize;
d->APELocation = -1;
d->APEOriginalSize = 0;
if(freeMemory)
if (freeMemory)
d->tag.set(APEIndex, 0);
}
return true;
}
void MPEG::File::setID3v2FrameFactory(const ID3v2::FrameFactory *factory)
{
void MPEG::File::setID3v2FrameFactory(const ID3v2::FrameFactory *factory) {
d->ID3v2FrameFactory = factory;
}
long MPEG::File::nextFrameOffset(long position)
{
long MPEG::File::nextFrameOffset(long position) {
ByteVector frameSyncBytes(2, '\0');
while(true) {
while (true) {
seek(position);
const ByteVector buffer = readBlock(bufferSize());
if(buffer.isEmpty())
if (buffer.isEmpty())
return -1;
for(unsigned int i = 0; i < buffer.size(); ++i) {
for (unsigned int i = 0; i < buffer.size(); ++i) {
frameSyncBytes[0] = frameSyncBytes[1];
frameSyncBytes[1] = buffer[i];
if(isFrameSync(frameSyncBytes)) {
if (isFrameSync(frameSyncBytes)) {
const Header header(this, position + i - 1, true);
if(header.isValid())
if (header.isValid())
return position + i - 1;
}
}
@@ -430,23 +400,22 @@ long MPEG::File::nextFrameOffset(long position)
}
}
long MPEG::File::previousFrameOffset(long position)
{
long MPEG::File::previousFrameOffset(long position) {
ByteVector frameSyncBytes(2, '\0');
while(position > 0) {
while (position > 0) {
const long bufferLength = std::min<long>(position, bufferSize());
position -= bufferLength;
seek(position);
const ByteVector buffer = readBlock(bufferLength);
for(int i = buffer.size() - 1; i >= 0; --i) {
for (int i = buffer.size() - 1; i >= 0; --i) {
frameSyncBytes[1] = frameSyncBytes[0];
frameSyncBytes[0] = buffer[i];
if(isFrameSync(frameSyncBytes)) {
if (isFrameSync(frameSyncBytes)) {
const Header header(this, position + i, true);
if(header.isValid())
if (header.isValid())
return position + i + header.frameLength();
}
}
@@ -455,23 +424,21 @@ long MPEG::File::previousFrameOffset(long position)
return -1;
}
long MPEG::File::firstFrameOffset()
{
long MPEG::File::firstFrameOffset() {
long position = 0;
if(hasID3v2Tag())
if (hasID3v2Tag())
position = d->ID3v2Location + ID3v2Tag()->header()->completeTagSize();
return nextFrameOffset(position);
}
long MPEG::File::lastFrameOffset()
{
long MPEG::File::lastFrameOffset() {
long position;
if(hasAPETag())
if (hasAPETag())
position = d->APELocation - 1;
else if(hasID3v1Tag())
else if (hasID3v1Tag())
position = d->ID3v1Location - 1;
else
position = length();
@@ -479,18 +446,15 @@ long MPEG::File::lastFrameOffset()
return previousFrameOffset(position);
}
bool MPEG::File::hasID3v1Tag() const
{
bool MPEG::File::hasID3v1Tag() const {
return (d->ID3v1Location >= 0);
}
bool MPEG::File::hasID3v2Tag() const
{
bool MPEG::File::hasID3v2Tag() const {
return (d->ID3v2Location >= 0);
}
bool MPEG::File::hasAPETag() const
{
bool MPEG::File::hasAPETag() const {
return (d->APELocation >= 0);
}
@@ -498,13 +462,12 @@ bool MPEG::File::hasAPETag() const
// private members
////////////////////////////////////////////////////////////////////////////////
void MPEG::File::read(bool readProperties)
{
void MPEG::File::read(bool readProperties) {
// Look for an ID3v2 tag
d->ID3v2Location = findID3v2();
if(d->ID3v2Location >= 0) {
if (d->ID3v2Location >= 0) {
d->tag.set(ID3v2Index, new ID3v2::Tag(this, d->ID3v2Location, d->ID3v2FrameFactory));
d->ID3v2OriginalSize = ID3v2Tag()->header()->completeTagSize();
}
@@ -513,20 +476,20 @@ void MPEG::File::read(bool readProperties)
d->ID3v1Location = Utils::findID3v1(this);
if(d->ID3v1Location >= 0)
if (d->ID3v1Location >= 0)
d->tag.set(ID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
// Look for an APE tag
d->APELocation = Utils::findAPE(this, d->ID3v1Location);
if(d->APELocation >= 0) {
if (d->APELocation >= 0) {
d->tag.set(APEIndex, new APE::Tag(this, d->APELocation));
d->APEOriginalSize = APETag()->footer()->completeTagSize();
d->APELocation = d->APELocation + APE::Footer::size() - d->APEOriginalSize;
}
if(readProperties)
if (readProperties)
d->properties = new Properties(this);
// Make sure that we have our default tag types available.
@@ -535,9 +498,8 @@ void MPEG::File::read(bool readProperties)
ID3v1Tag(true);
}
long MPEG::File::findID3v2()
{
if(!isValid())
long MPEG::File::findID3v2() {
if (!isValid())
return -1;
// An ID3v2 tag or MPEG frame is most likely be at the beginning of the file.
@@ -545,11 +507,11 @@ long MPEG::File::findID3v2()
const ByteVector headerID = ID3v2::Header::fileIdentifier();
seek(0);
if(readBlock(headerID.size()) == headerID)
if (readBlock(headerID.size()) == headerID)
return 0;
const Header firstHeader(this, 0, true);
if(firstHeader.isValid())
if (firstHeader.isValid())
return -1;
// Look for an ID3v2 tag until reaching the first valid MPEG frame.
@@ -558,25 +520,25 @@ long MPEG::File::findID3v2()
ByteVector tagHeaderBytes(3, '\0');
long position = 0;
while(true) {
while (true) {
seek(position);
const ByteVector buffer = readBlock(bufferSize());
if(buffer.isEmpty())
if (buffer.isEmpty())
return -1;
for(unsigned int i = 0; i < buffer.size(); ++i) {
for (unsigned int i = 0; i < buffer.size(); ++i) {
frameSyncBytes[0] = frameSyncBytes[1];
frameSyncBytes[1] = buffer[i];
if(isFrameSync(frameSyncBytes)) {
if (isFrameSync(frameSyncBytes)) {
const Header header(this, position + i - 1, true);
if(header.isValid())
if (header.isValid())
return -1;
}
tagHeaderBytes[0] = tagHeaderBytes[1];
tagHeaderBytes[1] = tagHeaderBytes[2];
tagHeaderBytes[2] = buffer[i];
if(tagHeaderBytes == headerID)
if (tagHeaderBytes == headerID)
return position + i - 2;
}

View File

@@ -37,43 +37,49 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace ID3v2 { class Tag; class FrameFactory; }
namespace ID3v1 { class Tag; }
namespace APE { class Tag; }
namespace ID3v2 {
class Tag;
class FrameFactory;
} // namespace ID3v2
namespace ID3v1 {
class Tag;
}
namespace APE {
class Tag;
}
//! An implementation of TagLib::File with MPEG (MP3) specific methods
//! An implementation of TagLib::File with MPEG (MP3) specific methods
namespace MPEG {
namespace MPEG {
//! An MPEG file class with some useful methods specific to MPEG
//! An MPEG file class with some useful methods specific to MPEG
/*!
/*!
* This implements the generic TagLib::File API and additionally provides
* access to properties that are distinct to MPEG files, notably access
* to the different ID3 tags.
*/
class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File
{
public:
/*!
class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
public:
/*!
* This set of flags is used for various operations and is suitable for
* being OR-ed together.
*/
enum TagTypes {
//! Empty set. Matches no tag types.
NoTags = 0x0000,
//! Matches ID3v1 tags.
ID3v1 = 0x0001,
//! Matches ID3v2 tags.
ID3v2 = 0x0002,
//! Matches APE tags.
APE = 0x0004,
//! Matches all tag types.
AllTags = 0xffff
};
enum TagTypes {
//! Empty set. Matches no tag types.
NoTags = 0x0000,
//! Matches ID3v1 tags.
ID3v1 = 0x0001,
//! Matches ID3v2 tags.
ID3v2 = 0x0002,
//! Matches APE tags.
APE = 0x0004,
//! Matches all tag types.
AllTags = 0xffff
};
/*!
/*!
* Constructs an MPEG file from \a file. If \a readProperties is true the
* file's audio properties will also be read.
*
@@ -82,10 +88,10 @@ namespace TagLib {
* \deprecated This constructor will be dropped in favor of the one below
* in a future version.
*/
File(FileName file, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
File(FileName file, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
/*!
* Constructs an MPEG file from \a file. If \a readProperties is true the
* file's audio properties will also be read.
*
@@ -94,12 +100,12 @@ namespace TagLib {
*
* \note In the current implementation, \a propertiesStyle is ignored.
*/
// BIC: merge with the above constructor
File(FileName file, ID3v2::FrameFactory *frameFactory,
bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
// BIC: merge with the above constructor
File(FileName file, ID3v2::FrameFactory *frameFactory,
bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
/*!
* Constructs an MPEG file from \a stream. If \a readProperties is true the
* file's audio properties will also be read.
*
@@ -111,16 +117,16 @@ namespace TagLib {
*
* \note In the current implementation, \a propertiesStyle is ignored.
*/
File(IOStream *stream, ID3v2::FrameFactory *frameFactory,
bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
File(IOStream *stream, ID3v2::FrameFactory *frameFactory,
bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
/*!
* Destroys this instance of the File.
*/
virtual ~File();
virtual ~File();
/*!
/*!
* Returns a pointer to a tag that is the union of the ID3v2 and ID3v1
* tags. The ID3v2 tag is given priority in reading the information -- if
* requested information exists in both the ID3v2 tag and the ID3v1 tag,
@@ -137,19 +143,19 @@ namespace TagLib {
* \see ID3v2Tag()
* \see APETag()
*/
virtual Tag *tag() const;
virtual Tag *tag() const;
/*!
/*!
* Implements the reading part of the unified property interface.
* If the file contains more than one tag, only the
* first one (in the order ID3v2, APE, ID3v1) will be converted to the
* PropertyMap.
*/
PropertyMap properties() const;
PropertyMap properties() const;
void removeUnsupportedProperties(const StringList &properties);
void removeUnsupportedProperties(const StringList &properties);
/*!
/*!
* Implements the writing part of the unified tag dictionary interface.
* In order to avoid problems with deprecated tag formats, this method
* always creates an ID3v2 tag if necessary.
@@ -157,15 +163,15 @@ namespace TagLib {
* limitations of that format.
* The returned PropertyMap refers to the ID3v2 tag only.
*/
PropertyMap setProperties(const PropertyMap &);
PropertyMap setProperties(const PropertyMap &);
/*!
/*!
* Returns the MPEG::Properties for this file. If no audio properties
* were read then this will return a null pointer.
*/
virtual Properties *audioProperties() const;
virtual Properties *audioProperties() const;
/*!
/*!
* Save the file. If at least one tag -- ID3v1 or ID3v2 -- exists this
* will duplicate its content into the other tag. This returns true
* if saving was successful.
@@ -180,9 +186,9 @@ namespace TagLib {
*
* \see save(int tags)
*/
virtual bool save();
virtual bool save();
/*!
/*!
* Save the file. This will attempt to save all of the tag types that are
* specified by OR-ing together TagTypes values. The save() method above
* uses AllTags. This returns true if saving was successful.
@@ -191,27 +197,27 @@ namespace TagLib {
* in memory, so later calls to save() which make use of these tags will
* remain valid. This also strips empty tags.
*/
bool save(int tags);
bool save(int tags);
/*!
/*!
* \deprecated
*/
// BIC: combine with the above method
TAGLIB_DEPRECATED bool save(int tags, bool stripOthers);
// BIC: combine with the above method
TAGLIB_DEPRECATED bool save(int tags, bool stripOthers);
/*!
/*!
* \deprecated
*/
// BIC: combine with the above method
TAGLIB_DEPRECATED bool save(int tags, bool stripOthers, int id3v2Version);
// BIC: combine with the above method
TAGLIB_DEPRECATED bool save(int tags, bool stripOthers, int id3v2Version);
/*!
/*!
* \deprecated
*/
// BIC: combine with the above method
TAGLIB_DEPRECATED bool save(int tags, bool stripOthers, int id3v2Version, bool duplicateTags);
// BIC: combine with the above method
TAGLIB_DEPRECATED bool save(int tags, bool stripOthers, int id3v2Version, bool duplicateTags);
/*!
/*!
* Save the file. This will attempt to save all of the tag types that are
* specified by OR-ing together TagTypes values.
*
@@ -224,11 +230,11 @@ namespace TagLib {
* If \a duplicate is set to DuplicateTags and at least one tag -- ID3v1
* or ID3v2 -- exists this will duplicate its content into the other tag.
*/
bool save(int tags, StripTags strip,
ID3v2::Version version = ID3v2::v4,
DuplicateTags duplicate = Duplicate);
bool save(int tags, StripTags strip,
ID3v2::Version version = ID3v2::v4,
DuplicateTags duplicate = Duplicate);
/*!
/*!
* Returns a pointer to the ID3v2 tag of the file.
*
* If \a create is false (the default) this may return a null pointer
@@ -245,9 +251,9 @@ namespace TagLib {
*
* \see hasID3v2Tag()
*/
ID3v2::Tag *ID3v2Tag(bool create = false);
ID3v2::Tag *ID3v2Tag(bool create = false);
/*!
/*!
* Returns a pointer to the ID3v1 tag of the file.
*
* If \a create is false (the default) this may return a null pointer
@@ -264,9 +270,9 @@ namespace TagLib {
*
* \see hasID3v1Tag()
*/
ID3v1::Tag *ID3v1Tag(bool create = false);
ID3v1::Tag *ID3v1Tag(bool create = false);
/*!
/*!
* Returns a pointer to the APE tag of the file.
*
* If \a create is false (the default) this may return a null pointer
@@ -283,9 +289,9 @@ namespace TagLib {
*
* \see hasAPETag()
*/
APE::Tag *APETag(bool create = false);
APE::Tag *APETag(bool create = false);
/*!
/*!
* This will strip the tags that match the OR-ed together TagTypes from the
* file. By default it strips all tags. It returns true if the tags are
* successfully stripped.
@@ -297,9 +303,9 @@ namespace TagLib {
*
* \note This will update the file immediately.
*/
bool strip(int tags = AllTags);
bool strip(int tags = AllTags);
/*!
/*!
* This will strip the tags that match the OR-ed together TagTypes from the
* file. By default it strips all tags. It returns true if the tags are
* successfully stripped.
@@ -309,81 +315,81 @@ namespace TagLib {
*
* \note This will update the file immediately.
*/
// BIC: merge with the method above
bool strip(int tags, bool freeMemory);
// BIC: merge with the method above
bool strip(int tags, bool freeMemory);
/*!
/*!
* Set the ID3v2::FrameFactory to something other than the default.
*
* \see ID3v2FrameFactory
* \deprecated This value should be passed in via the constructor
*/
TAGLIB_DEPRECATED void setID3v2FrameFactory(const ID3v2::FrameFactory *factory);
TAGLIB_DEPRECATED void setID3v2FrameFactory(const ID3v2::FrameFactory *factory);
/*!
/*!
* Returns the position in the file of the first MPEG frame.
*/
long firstFrameOffset();
long firstFrameOffset();
/*!
/*!
* Returns the position in the file of the next MPEG frame,
* using the current position as start
*/
long nextFrameOffset(long position);
long nextFrameOffset(long position);
/*!
/*!
* Returns the position in the file of the previous MPEG frame,
* using the current position as start
*/
long previousFrameOffset(long position);
long previousFrameOffset(long position);
/*!
/*!
* Returns the position in the file of the last MPEG frame.
*/
long lastFrameOffset();
long lastFrameOffset();
/*!
/*!
* Returns whether or not the file on disk actually has an ID3v1 tag.
*
* \see ID3v1Tag()
*/
bool hasID3v1Tag() const;
bool hasID3v1Tag() const;
/*!
/*!
* Returns whether or not the file on disk actually has an ID3v2 tag.
*
* \see ID3v2Tag()
*/
bool hasID3v2Tag() const;
bool hasID3v2Tag() const;
/*!
/*!
* Returns whether or not the file on disk actually has an APE tag.
*
* \see APETag()
*/
bool hasAPETag() const;
bool hasAPETag() const;
/*!
/*!
* Returns whether or not the given \a stream can be opened as an MPEG
* file.
*
* \note This method is designed to do a quick check. The result may
* not necessarily be correct.
*/
static bool isSupported(IOStream *stream);
static bool isSupported(IOStream *stream);
private:
File(const File &);
File &operator=(const File &);
private:
File(const File &);
File &operator=(const File &);
void read(bool readProperties);
long findID3v2();
void read(bool readProperties);
long findID3v2();
class FilePrivate;
FilePrivate *d;
};
}
}
}
class FilePrivate;
FilePrivate *d;
};
} // namespace MPEG
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -34,22 +34,20 @@
using namespace Strawberry_TagLib::TagLib;
class MPEG::Header::HeaderPrivate : public RefCounter
{
public:
HeaderPrivate() :
isValid(false),
version(Version1),
layer(0),
protectionEnabled(false),
bitrate(0),
sampleRate(0),
isPadded(false),
channelMode(Stereo),
isCopyrighted(false),
isOriginal(false),
frameLength(0),
samplesPerFrame(0) {}
class MPEG::Header::HeaderPrivate : public RefCounter {
public:
HeaderPrivate() : isValid(false),
version(Version1),
layer(0),
protectionEnabled(false),
bitrate(0),
sampleRate(0),
isPadded(false),
channelMode(Stereo),
isCopyrighted(false),
isOriginal(false),
frameLength(0),
samplesPerFrame(0) {}
bool isValid;
Version version;
@@ -69,96 +67,76 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
MPEG::Header::Header(const ByteVector&) :
d(new HeaderPrivate())
{
MPEG::Header::Header(const ByteVector &) : d(new HeaderPrivate()) {
debug("MPEG::Header::Header() - This constructor is no longer used.");
}
MPEG::Header::Header(File *file, long offset, bool checkLength) :
d(new HeaderPrivate())
{
MPEG::Header::Header(File *file, long offset, bool checkLength) : d(new HeaderPrivate()) {
parse(file, offset, checkLength);
}
MPEG::Header::Header(const Header &h) :
d(h.d)
{
MPEG::Header::Header(const Header &h) : d(h.d) {
d->ref();
}
MPEG::Header::~Header()
{
if(d->deref())
MPEG::Header::~Header() {
if (d->deref())
delete d;
}
bool MPEG::Header::isValid() const
{
bool MPEG::Header::isValid() const {
return d->isValid;
}
MPEG::Header::Version MPEG::Header::version() const
{
MPEG::Header::Version MPEG::Header::version() const {
return d->version;
}
int MPEG::Header::layer() const
{
int MPEG::Header::layer() const {
return d->layer;
}
bool MPEG::Header::protectionEnabled() const
{
bool MPEG::Header::protectionEnabled() const {
return d->protectionEnabled;
}
int MPEG::Header::bitrate() const
{
int MPEG::Header::bitrate() const {
return d->bitrate;
}
int MPEG::Header::sampleRate() const
{
int MPEG::Header::sampleRate() const {
return d->sampleRate;
}
bool MPEG::Header::isPadded() const
{
bool MPEG::Header::isPadded() const {
return d->isPadded;
}
MPEG::Header::ChannelMode MPEG::Header::channelMode() const
{
MPEG::Header::ChannelMode MPEG::Header::channelMode() const {
return d->channelMode;
}
bool MPEG::Header::isCopyrighted() const
{
bool MPEG::Header::isCopyrighted() const {
return d->isCopyrighted;
}
bool MPEG::Header::isOriginal() const
{
bool MPEG::Header::isOriginal() const {
return d->isOriginal;
}
int MPEG::Header::frameLength() const
{
int MPEG::Header::frameLength() const {
return d->frameLength;
}
int MPEG::Header::samplesPerFrame() const
{
int MPEG::Header::samplesPerFrame() const {
return d->samplesPerFrame;
}
MPEG::Header &MPEG::Header::operator=(const Header &h)
{
if(&h == this)
MPEG::Header &MPEG::Header::operator=(const Header &h) {
if (&h == this)
return *this;
if(d->deref())
if (d->deref())
delete d;
d = h.d;
@@ -170,19 +148,18 @@ MPEG::Header &MPEG::Header::operator=(const Header &h)
// private members
////////////////////////////////////////////////////////////////////////////////
void MPEG::Header::parse(File *file, long offset, bool checkLength)
{
void MPEG::Header::parse(File *file, long offset, bool checkLength) {
file->seek(offset);
const ByteVector data = file->readBlock(4);
if(data.size() < 4) {
if (data.size() < 4) {
debug("MPEG::Header::parse() -- data is too short for an MPEG frame header.");
return;
}
// Check for the MPEG synch bytes.
if(!isFrameSync(data)) {
if (!isFrameSync(data)) {
debug("MPEG::Header::parse() -- MPEG header did not match MPEG synch.");
return;
}
@@ -191,11 +168,11 @@ void MPEG::Header::parse(File *file, long offset, bool checkLength)
const int versionBits = (static_cast<unsigned char>(data[1]) >> 3) & 0x03;
if(versionBits == 0)
if (versionBits == 0)
d->version = Version2_5;
else if(versionBits == 2)
else if (versionBits == 2)
d->version = Version2;
else if(versionBits == 3)
else if (versionBits == 3)
d->version = Version1;
else
return;
@@ -204,11 +181,11 @@ void MPEG::Header::parse(File *file, long offset, bool checkLength)
const int layerBits = (static_cast<unsigned char>(data[1]) >> 1) & 0x03;
if(layerBits == 1)
if (layerBits == 1)
d->layer = 3;
else if(layerBits == 2)
else if (layerBits == 2)
d->layer = 2;
else if(layerBits == 3)
else if (layerBits == 3)
d->layer = 1;
else
return;
@@ -218,20 +195,22 @@ void MPEG::Header::parse(File *file, long offset, bool checkLength)
// Set the bitrate
static const int bitrates[2][3][16] = {
{ // Version 1
{ 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0 }, // layer 1
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0 }, // layer 2
{ 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 } // layer 3
{
// Version 1
{ 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0 }, // layer 1
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0 }, // layer 2
{ 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 } // layer 3
},
{ // Version 2 or 2.5
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0 }, // layer 1
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 }, // layer 2
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 } // layer 3
{
// Version 2 or 2.5
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0 }, // layer 1
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 }, // layer 2
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 } // layer 3
}
};
const int versionIndex = (d->version == Version1) ? 0 : 1;
const int layerIndex = (d->layer > 0) ? d->layer - 1 : 0;
const int layerIndex = (d->layer > 0) ? d->layer - 1 : 0;
// The bitrate index is encoded as the first 4 bits of the 3rd byte,
// i.e. 1111xxxx
@@ -240,15 +219,15 @@ void MPEG::Header::parse(File *file, long offset, bool checkLength)
d->bitrate = bitrates[versionIndex][layerIndex][bitrateIndex];
if(d->bitrate == 0)
if (d->bitrate == 0)
return;
// Set the sample rate
static const int sampleRates[3][4] = {
{ 44100, 48000, 32000, 0 }, // Version 1
{ 22050, 24000, 16000, 0 }, // Version 2
{ 11025, 12000, 8000, 0 } // Version 2.5
{ 44100, 48000, 32000, 0 }, // Version 1
{ 22050, 24000, 16000, 0 }, // Version 2
{ 11025, 12000, 8000, 0 } // Version 2.5
};
// The sample rate index is encoded as two bits in the 3nd byte, i.e. xxxx11xx
@@ -257,7 +236,7 @@ void MPEG::Header::parse(File *file, long offset, bool checkLength)
d->sampleRate = sampleRates[d->version][samplerateIndex];
if(d->sampleRate == 0) {
if (d->sampleRate == 0) {
return;
}
@@ -268,17 +247,17 @@ void MPEG::Header::parse(File *file, long offset, bool checkLength)
// TODO: Add mode extension for completeness
d->isOriginal = ((static_cast<unsigned char>(data[3]) & 0x04) != 0);
d->isOriginal = ((static_cast<unsigned char>(data[3]) & 0x04) != 0);
d->isCopyrighted = ((static_cast<unsigned char>(data[3]) & 0x08) != 0);
d->isPadded = ((static_cast<unsigned char>(data[2]) & 0x02) != 0);
d->isPadded = ((static_cast<unsigned char>(data[2]) & 0x02) != 0);
// Samples per frame
static const int samplesPerFrame[3][2] = {
// MPEG1, 2/2.5
{ 384, 384 }, // Layer I
{ 1152, 1152 }, // Layer II
{ 1152, 576 } // Layer III
{ 384, 384 }, // Layer I
{ 1152, 1152 }, // Layer II
{ 1152, 576 } // Layer III
};
d->samplesPerFrame = samplesPerFrame[layerIndex][versionIndex];
@@ -289,10 +268,10 @@ void MPEG::Header::parse(File *file, long offset, bool checkLength)
d->frameLength = d->samplesPerFrame * d->bitrate * 125 / d->sampleRate;
if(d->isPadded)
if (d->isPadded)
d->frameLength += paddingSize[layerIndex];
if(checkLength) {
if (checkLength) {
// Check if the frame length has been calculated correctly, or the next frame
// header is right next to the end of this frame.
@@ -304,15 +283,15 @@ void MPEG::Header::parse(File *file, long offset, bool checkLength)
file->seek(offset + d->frameLength);
const ByteVector nextData = file->readBlock(4);
if(nextData.size() < 4)
if (nextData.size() < 4)
return;
const unsigned int HeaderMask = 0xfffe0c00;
const unsigned int header = data.toUInt(0, true) & HeaderMask;
const unsigned int header = data.toUInt(0, true) & HeaderMask;
const unsigned int nextHeader = nextData.toUInt(0, true) & HeaderMask;
if(header != nextHeader)
if (header != nextHeader)
return;
}

View File

@@ -31,150 +31,149 @@
namespace Strawberry_TagLib {
namespace TagLib {
class ByteVector;
class File;
class ByteVector;
class File;
namespace MPEG {
namespace MPEG {
//! An implementation of MP3 frame headers
//! An implementation of MP3 frame headers
/*!
/*!
* This is an implementation of MPEG Layer III headers. The API follows more
* or less the binary format of these headers. I've used
* <a href="http://www.mp3-tech.org/programmer/frame_header.html">this</a>
* document as a reference.
*/
class TAGLIB_EXPORT Header
{
public:
/*!
class TAGLIB_EXPORT Header {
public:
/*!
* Parses an MPEG header based on \a data.
*
* \deprecated
*/
TAGLIB_DEPRECATED Header(const ByteVector &data);
TAGLIB_DEPRECATED Header(const ByteVector &data);
/*!
/*!
* Parses an MPEG header based on \a file and \a offset.
*
* \note If \a checkLength is true, this requires the next MPEG frame to
* check if the frame length is parsed and calculated correctly. So it's
* suitable for seeking for the first valid frame.
*/
Header(File *file, long offset, bool checkLength = true);
Header(File *file, long offset, bool checkLength = true);
/*!
/*!
* Does a shallow copy of \a h.
*/
Header(const Header &h);
Header(const Header &h);
/*!
/*!
* Destroys this Header instance.
*/
virtual ~Header();
virtual ~Header();
/*!
/*!
* Returns true if the frame is at least an appropriate size and has
* legal values.
*/
bool isValid() const;
bool isValid() const;
/*!
/*!
* The MPEG Version.
*/
enum Version {
//! MPEG Version 1
Version1 = 0,
//! MPEG Version 2
Version2 = 1,
//! MPEG Version 2.5
Version2_5 = 2
};
enum Version {
//! MPEG Version 1
Version1 = 0,
//! MPEG Version 2
Version2 = 1,
//! MPEG Version 2.5
Version2_5 = 2
};
/*!
/*!
* Returns the MPEG Version of the header.
*/
Version version() const;
Version version() const;
/*!
/*!
* Returns the layer version. This will be between the values 1-3.
*/
int layer() const;
int layer() const;
/*!
/*!
* Returns true if the MPEG protection bit is enabled.
*/
bool protectionEnabled() const;
bool protectionEnabled() const;
/*!
/*!
* Returns the bitrate encoded in the header.
*/
int bitrate() const;
int bitrate() const;
/*!
/*!
* Returns the sample rate in Hz.
*/
int sampleRate() const;
int sampleRate() const;
/*!
/*!
* Returns true if the frame is padded.
*/
bool isPadded() const;
bool isPadded() const;
/*!
/*!
* There are a few combinations or one or two channel audio that are
* possible:
*/
enum ChannelMode {
//! Stereo
Stereo = 0,
//! Stereo
JointStereo = 1,
//! Dual Mono
DualChannel = 2,
//! Mono
SingleChannel = 3
};
enum ChannelMode {
//! Stereo
Stereo = 0,
//! Stereo
JointStereo = 1,
//! Dual Mono
DualChannel = 2,
//! Mono
SingleChannel = 3
};
/*!
/*!
* Returns the channel mode for this frame.
*/
ChannelMode channelMode() const;
ChannelMode channelMode() const;
/*!
/*!
* Returns true if the copyrighted bit is set.
*/
bool isCopyrighted() const;
bool isCopyrighted() const;
/*!
/*!
* Returns true if the "original" bit is set.
*/
bool isOriginal() const;
bool isOriginal() const;
/*!
/*!
* Returns the frame length in bytes.
*/
int frameLength() const;
int frameLength() const;
/*!
/*!
* Returns the number of frames per sample.
*/
int samplesPerFrame() const;
int samplesPerFrame() const;
/*!
/*!
* Makes a shallow copy of the header.
*/
Header &operator=(const Header &h);
Header &operator=(const Header &h);
private:
void parse(File *file, long offset, bool checkLength);
private:
void parse(File *file, long offset, bool checkLength);
class HeaderPrivate;
HeaderPrivate *d;
};
}
}
}
class HeaderPrivate;
HeaderPrivate *d;
};
} // namespace MPEG
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -34,24 +34,21 @@
using namespace Strawberry_TagLib::TagLib;
class MPEG::Properties::PropertiesPrivate
{
public:
PropertiesPrivate() :
xingHeader(0),
length(0),
bitrate(0),
sampleRate(0),
channels(0),
layer(0),
version(Header::Version1),
channelMode(Header::Stereo),
protectionEnabled(false),
isCopyrighted(false),
isOriginal(false) {}
class MPEG::Properties::PropertiesPrivate {
public:
PropertiesPrivate() : xingHeader(0),
length(0),
bitrate(0),
sampleRate(0),
channels(0),
layer(0),
version(Header::Version1),
channelMode(Header::Stereo),
protectionEnabled(false),
isCopyrighted(false),
isOriginal(false) {}
~PropertiesPrivate()
{
~PropertiesPrivate() {
delete xingHeader;
}
@@ -72,80 +69,64 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
MPEG::Properties::Properties(File *file, ReadStyle style) :
AudioProperties(style),
d(new PropertiesPrivate())
{
MPEG::Properties::Properties(File *file, ReadStyle style) : AudioProperties(style),
d(new PropertiesPrivate()) {
read(file);
}
MPEG::Properties::~Properties()
{
MPEG::Properties::~Properties() {
delete d;
}
int MPEG::Properties::length() const
{
int MPEG::Properties::length() const {
return lengthInSeconds();
}
int MPEG::Properties::lengthInSeconds() const
{
int MPEG::Properties::lengthInSeconds() const {
return d->length / 1000;
}
int MPEG::Properties::lengthInMilliseconds() const
{
int MPEG::Properties::lengthInMilliseconds() const {
return d->length;
}
int MPEG::Properties::bitrate() const
{
int MPEG::Properties::bitrate() const {
return d->bitrate;
}
int MPEG::Properties::sampleRate() const
{
int MPEG::Properties::sampleRate() const {
return d->sampleRate;
}
int MPEG::Properties::channels() const
{
int MPEG::Properties::channels() const {
return d->channels;
}
const MPEG::XingHeader *MPEG::Properties::xingHeader() const
{
const MPEG::XingHeader *MPEG::Properties::xingHeader() const {
return d->xingHeader;
}
MPEG::Header::Version MPEG::Properties::version() const
{
MPEG::Header::Version MPEG::Properties::version() const {
return d->version;
}
int MPEG::Properties::layer() const
{
int MPEG::Properties::layer() const {
return d->layer;
}
bool MPEG::Properties::protectionEnabled() const
{
bool MPEG::Properties::protectionEnabled() const {
return d->protectionEnabled;
}
MPEG::Header::ChannelMode MPEG::Properties::channelMode() const
{
MPEG::Header::ChannelMode MPEG::Properties::channelMode() const {
return d->channelMode;
}
bool MPEG::Properties::isCopyrighted() const
{
bool MPEG::Properties::isCopyrighted() const {
return d->isCopyrighted;
}
bool MPEG::Properties::isOriginal() const
{
bool MPEG::Properties::isOriginal() const {
return d->isOriginal;
}
@@ -153,12 +134,11 @@ bool MPEG::Properties::isOriginal() const
// private members
////////////////////////////////////////////////////////////////////////////////
void MPEG::Properties::read(File *file)
{
void MPEG::Properties::read(File *file) {
// Only the first valid frame is required if we have a VBR header.
const long firstFrameOffset = file->firstFrameOffset();
if(firstFrameOffset < 0) {
if (firstFrameOffset < 0) {
debug("MPEG::Properties::read() -- Could not find an MPEG frame in the stream.");
return;
}
@@ -170,22 +150,22 @@ void MPEG::Properties::read(File *file)
file->seek(firstFrameOffset);
d->xingHeader = new XingHeader(file->readBlock(firstHeader.frameLength()));
if(!d->xingHeader->isValid()) {
if (!d->xingHeader->isValid()) {
delete d->xingHeader;
d->xingHeader = 0;
}
if(d->xingHeader && firstHeader.samplesPerFrame() > 0 && firstHeader.sampleRate() > 0) {
if (d->xingHeader && firstHeader.samplesPerFrame() > 0 && firstHeader.sampleRate() > 0) {
// Read the length and the bitrate from the VBR header.
const double timePerFrame = firstHeader.samplesPerFrame() * 1000.0 / firstHeader.sampleRate();
const double length = timePerFrame * d->xingHeader->totalFrames();
d->length = static_cast<int>(length + 0.5);
d->length = static_cast<int>(length + 0.5);
d->bitrate = static_cast<int>(d->xingHeader->totalSize() * 8.0 / length + 0.5);
}
else if(firstHeader.bitrate() > 0) {
else if (firstHeader.bitrate() > 0) {
// Since there was no valid VBR header found, we hope that we're in a constant
// bitrate file.
@@ -198,23 +178,23 @@ void MPEG::Properties::read(File *file)
// Look for the last MPEG audio frame to calculate the stream length.
const long lastFrameOffset = file->lastFrameOffset();
if(lastFrameOffset < 0) {
if (lastFrameOffset < 0) {
debug("MPEG::Properties::read() -- Could not find an MPEG frame in the stream.");
return;
}
const Header lastHeader(file, lastFrameOffset, false);
const long streamLength = lastFrameOffset - firstFrameOffset + lastHeader.frameLength();
if(streamLength > 0)
if (streamLength > 0)
d->length = static_cast<int>(streamLength * 8.0 / d->bitrate + 0.5);
}
d->sampleRate = firstHeader.sampleRate();
d->channels = firstHeader.channelMode() == Header::SingleChannel ? 1 : 2;
d->version = firstHeader.version();
d->layer = firstHeader.layer();
d->sampleRate = firstHeader.sampleRate();
d->channels = firstHeader.channelMode() == Header::SingleChannel ? 1 : 2;
d->version = firstHeader.version();
d->layer = firstHeader.layer();
d->protectionEnabled = firstHeader.protectionEnabled();
d->channelMode = firstHeader.channelMode();
d->isCopyrighted = firstHeader.isCopyrighted();
d->isOriginal = firstHeader.isOriginal();
d->channelMode = firstHeader.channelMode();
d->isCopyrighted = firstHeader.isCopyrighted();
d->isOriginal = firstHeader.isOriginal();
}

View File

@@ -34,33 +34,32 @@
namespace Strawberry_TagLib {
namespace TagLib {
namespace MPEG {
namespace MPEG {
class File;
class XingHeader;
class File;
class XingHeader;
//! An implementation of audio property reading for MP3
//! An implementation of audio property reading for MP3
/*!
/*!
* This reads the data from an MPEG Layer III stream found in the
* AudioProperties API.
*/
class TAGLIB_EXPORT Properties : public AudioProperties
{
public:
/*!
class TAGLIB_EXPORT Properties : public AudioProperties {
public:
/*!
* Create an instance of MPEG::Properties with the data read from the
* MPEG::File \a file.
*/
Properties(File *file, ReadStyle style = Average);
Properties(File *file, ReadStyle style = Average);
/*!
/*!
* Destroys this MPEG Properties instance.
*/
virtual ~Properties();
virtual ~Properties();
/*!
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
@@ -68,87 +67,87 @@ namespace TagLib {
*
* \deprecated
*/
virtual int length() const;
virtual int length() const;
/*!
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
* \see lengthInMilliseconds()
*/
// BIC: make virtual
int lengthInSeconds() const;
// BIC: make virtual
int lengthInSeconds() const;
/*!
/*!
* Returns the length of the file in milliseconds.
*
* \see lengthInSeconds()
*/
// BIC: make virtual
int lengthInMilliseconds() const;
// BIC: make virtual
int lengthInMilliseconds() const;
/*!
/*!
* Returns the average bit rate of the file in kb/s.
*/
virtual int bitrate() const;
virtual int bitrate() const;
/*!
/*!
* Returns the sample rate in Hz.
*/
virtual int sampleRate() const;
virtual int sampleRate() const;
/*!
/*!
* Returns the number of audio channels.
*/
virtual int channels() const;
virtual int channels() const;
/*!
/*!
* Returns a pointer to the Xing/VBRI header if one exists or null if no
* Xing/VBRI header was found.
*/
const XingHeader *xingHeader() const;
const XingHeader *xingHeader() const;
/*!
/*!
* Returns the MPEG Version of the file.
*/
Header::Version version() const;
Header::Version version() const;
/*!
/*!
* Returns the layer version. This will be between the values 1-3.
*/
int layer() const;
int layer() const;
/*!
/*!
* Returns true if the MPEG protection bit is enabled.
*/
bool protectionEnabled() const;
bool protectionEnabled() const;
/*!
/*!
* Returns the channel mode for this frame.
*/
Header::ChannelMode channelMode() const;
Header::ChannelMode channelMode() const;
/*!
/*!
* Returns true if the copyrighted bit is set.
*/
bool isCopyrighted() const;
bool isCopyrighted() const;
/*!
/*!
* Returns true if the "original" bit is set.
*/
bool isOriginal() const;
bool isOriginal() const;
private:
Properties(const Properties &);
Properties &operator=(const Properties &);
private:
Properties(const Properties &);
Properties &operator=(const Properties &);
void read(File *file);
void read(File *file);
class PropertiesPrivate;
PropertiesPrivate *d;
};
}
}
}
class PropertiesPrivate;
PropertiesPrivate *d;
};
} // namespace MPEG
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -31,14 +31,11 @@
#ifndef DO_NOT_DOCUMENT // tell Doxygen not to document this header
namespace Strawberry_TagLib {
namespace TagLib
{
namespace MPEG
{
namespace
{
namespace TagLib {
namespace MPEG {
namespace {
/*!
/*!
* MPEG frames can be recognized by the bit pattern 11111111 111, so the
* first byte is easy to check for, however checking to see if the second byte
* starts with \e 111 is a bit more tricky, hence these functions.
@@ -46,19 +43,18 @@ namespace TagLib
* \note This does not check the length of the vector, since this is an
* internal utility function.
*/
inline bool isFrameSync(const ByteVector &bytes, unsigned int offset = 0)
{
// 0xFF in the second byte is possible in theory, but it's very unlikely.
inline bool isFrameSync(const ByteVector &bytes, unsigned int offset = 0) {
// 0xFF in the second byte is possible in theory, but it's very unlikely.
const unsigned char b1 = bytes[offset + 0];
const unsigned char b2 = bytes[offset + 1];
return (b1 == 0xFF && b2 != 0xFF && (b2 & 0xE0) == 0xE0);
}
const unsigned char b1 = bytes[offset + 0];
const unsigned char b2 = bytes[offset + 1];
return (b1 == 0xFF && b2 != 0xFF && (b2 & 0xE0) == 0xE0);
}
}
}
}
}
} // namespace
} // namespace MPEG
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif

View File

@@ -32,13 +32,11 @@
using namespace Strawberry_TagLib::TagLib;
class MPEG::XingHeader::XingHeaderPrivate
{
public:
XingHeaderPrivate() :
frames(0),
size(0),
type(MPEG::XingHeader::Invalid) {}
class MPEG::XingHeader::XingHeaderPrivate {
public:
XingHeaderPrivate() : frames(0),
size(0),
type(MPEG::XingHeader::Invalid) {}
unsigned int frames;
unsigned int size;
@@ -50,40 +48,32 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
MPEG::XingHeader::XingHeader(const ByteVector &data) :
d(new XingHeaderPrivate())
{
MPEG::XingHeader::XingHeader(const ByteVector &data) : d(new XingHeaderPrivate()) {
parse(data);
}
MPEG::XingHeader::~XingHeader()
{
MPEG::XingHeader::~XingHeader() {
delete d;
}
bool MPEG::XingHeader::isValid() const
{
bool MPEG::XingHeader::isValid() const {
return (d->type != Invalid && d->frames > 0 && d->size > 0);
}
unsigned int MPEG::XingHeader::totalFrames() const
{
unsigned int MPEG::XingHeader::totalFrames() const {
return d->frames;
}
unsigned int MPEG::XingHeader::totalSize() const
{
unsigned int MPEG::XingHeader::totalSize() const {
return d->size;
}
MPEG::XingHeader::HeaderType MPEG::XingHeader::type() const
{
MPEG::XingHeader::HeaderType MPEG::XingHeader::type() const {
return d->type;
}
int MPEG::XingHeader::xingHeaderOffset(Strawberry_TagLib::TagLib::MPEG::Header::Version /*v*/,
Strawberry_TagLib::TagLib::MPEG::Header::ChannelMode /*c*/)
{
Strawberry_TagLib::TagLib::MPEG::Header::ChannelMode /*c*/) {
return 0;
}
@@ -91,31 +81,30 @@ int MPEG::XingHeader::xingHeaderOffset(Strawberry_TagLib::TagLib::MPEG::Header::
// private members
////////////////////////////////////////////////////////////////////////////////
void MPEG::XingHeader::parse(const ByteVector &data)
{
void MPEG::XingHeader::parse(const ByteVector &data) {
// Look for a Xing header.
long offset = data.find("Xing");
if(offset < 0)
if (offset < 0)
offset = data.find("Info");
if(offset >= 0) {
if (offset >= 0) {
// Xing header found.
if(data.size() < static_cast<unsigned long>(offset + 16)) {
if (data.size() < static_cast<unsigned long>(offset + 16)) {
debug("MPEG::XingHeader::parse() -- Xing header found but too short.");
return;
}
if((data[offset + 7] & 0x03) != 0x03) {
if ((data[offset + 7] & 0x03) != 0x03) {
debug("MPEG::XingHeader::parse() -- Xing header doesn't contain the required information.");
return;
}
d->frames = data.toUInt(offset + 8, true);
d->size = data.toUInt(offset + 12, true);
d->type = Xing;
d->frames = data.toUInt(offset + 8, true);
d->size = data.toUInt(offset + 12, true);
d->type = Xing;
}
else {
@@ -123,18 +112,18 @@ void MPEG::XingHeader::parse(const ByteVector &data)
offset = data.find("VBRI");
if(offset >= 0) {
if (offset >= 0) {
// VBRI header found.
if(data.size() < static_cast<unsigned long>(offset + 32)) {
if (data.size() < static_cast<unsigned long>(offset + 32)) {
debug("MPEG::XingHeader::parse() -- VBRI header found but too short.");
return;
}
d->frames = data.toUInt(offset + 14, true);
d->size = data.toUInt(offset + 10, true);
d->type = VBRI;
d->size = data.toUInt(offset + 10, true);
d->type = VBRI;
}
}
}

View File

@@ -32,15 +32,15 @@
namespace Strawberry_TagLib {
namespace TagLib {
class ByteVector;
class ByteVector;
namespace MPEG {
namespace MPEG {
class File;
class File;
//! An implementation of the Xing/VBRI headers
//! An implementation of the Xing/VBRI headers
/*!
/*!
* This is a minimalistic implementation of the Xing/VBRI VBR headers.
* Xing/VBRI headers are often added to VBR (variable bit rate) MP3 streams
* to make it easy to compute the length and quality of a VBR stream. Our
@@ -50,82 +50,80 @@ namespace TagLib {
* this text</a> and the XMMS sources as references.
*/
class TAGLIB_EXPORT XingHeader
{
public:
/*!
class TAGLIB_EXPORT XingHeader {
public:
/*!
* The type of the VBR header.
*/
enum HeaderType
{
/*!
enum HeaderType {
/*!
* Invalid header or no VBR header found.
*/
Invalid = 0,
Invalid = 0,
/*!
/*!
* Xing header.
*/
Xing = 1,
Xing = 1,
/*!
/*!
* VBRI header.
*/
VBRI = 2,
};
VBRI = 2,
};
/*!
/*!
* Parses an Xing/VBRI header based on \a data which contains the entire
* first MPEG frame.
*/
XingHeader(const ByteVector &data);
XingHeader(const ByteVector &data);
/*!
/*!
* Destroy this XingHeader instance.
*/
virtual ~XingHeader();
virtual ~XingHeader();
/*!
/*!
* Returns true if the data was parsed properly and if there is a valid
* Xing/VBRI header present.
*/
bool isValid() const;
bool isValid() const;
/*!
/*!
* Returns the total number of frames.
*/
unsigned int totalFrames() const;
unsigned int totalFrames() const;
/*!
/*!
* Returns the total size of stream in bytes.
*/
unsigned int totalSize() const;
unsigned int totalSize() const;
/*!
/*!
* Returns the type of the VBR header.
*/
HeaderType type() const;
HeaderType type() const;
/*!
/*!
* Returns the offset for the start of this Xing header, given the
* version and channels of the frame
*
* \deprecated Always returns 0.
*/
TAGLIB_DEPRECATED static int xingHeaderOffset(Strawberry_TagLib::TagLib::MPEG::Header::Version v,
Strawberry_TagLib::TagLib::MPEG::Header::ChannelMode c);
TAGLIB_DEPRECATED static int xingHeaderOffset(Strawberry_TagLib::TagLib::MPEG::Header::Version v,
Strawberry_TagLib::TagLib::MPEG::Header::ChannelMode c);
private:
XingHeader(const XingHeader &);
XingHeader &operator=(const XingHeader &);
private:
XingHeader(const XingHeader &);
XingHeader &operator=(const XingHeader &);
void parse(const ByteVector &data);
void parse(const ByteVector &data);
class XingHeaderPrivate;
XingHeaderPrivate *d;
};
}
}
}
class XingHeaderPrivate;
XingHeaderPrivate *d;
};
} // namespace MPEG
} // namespace TagLib
} // namespace Strawberry_TagLib
#endif