Audio file detection by content
This commit is contained in:
265
3rdparty/taglib/mpeg/id3v1/id3v1genres.cpp
vendored
Normal file
265
3rdparty/taglib/mpeg/id3v1/id3v1genres.cpp
vendored
Normal file
@@ -0,0 +1,265 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include "id3v1genres.h"
|
||||
|
||||
using namespace 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]);
|
||||
}
|
||||
|
||||
StringList ID3v1::genreList()
|
||||
{
|
||||
StringList l;
|
||||
for(int i = 0; i < genresSize; i++) {
|
||||
l.append(genres[i]);
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
ID3v1::GenreMap ID3v1::genreMap()
|
||||
{
|
||||
GenreMap m;
|
||||
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
|
||||
else
|
||||
return String();
|
||||
}
|
||||
|
||||
int ID3v1::genreIndex(const String &name)
|
||||
{
|
||||
for(int i = 0; i < genresSize; ++i) {
|
||||
if(name == genres[i])
|
||||
return i;
|
||||
}
|
||||
|
||||
return 255;
|
||||
}
|
||||
66
3rdparty/taglib/mpeg/id3v1/id3v1genres.h
vendored
Normal file
66
3rdparty/taglib/mpeg/id3v1/id3v1genres.h
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_ID3V1GENRE_H
|
||||
#define TAGLIB_ID3V1GENRE_H
|
||||
|
||||
#include "tmap.h"
|
||||
#include "tstringlist.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
namespace ID3v1 {
|
||||
|
||||
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();
|
||||
|
||||
/*!
|
||||
* A "reverse mapping" that goes from the canonical ID3v1 genre name to the
|
||||
* respective genre number. genreMap()["Rock"] ==
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
270
3rdparty/taglib/mpeg/id3v1/id3v1tag.cpp
vendored
Normal file
270
3rdparty/taglib/mpeg/id3v1/id3v1tag.cpp
vendored
Normal file
@@ -0,0 +1,270 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tdebug.h>
|
||||
#include <tfile.h>
|
||||
|
||||
#include "id3v1tag.h"
|
||||
#include "id3v1genres.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v1;
|
||||
|
||||
namespace
|
||||
{
|
||||
const ID3v1::StringHandler defaultStringHandler;
|
||||
const ID3v1::StringHandler *stringHandler = &defaultStringHandler;
|
||||
}
|
||||
|
||||
class ID3v1::Tag::TagPrivate
|
||||
{
|
||||
public:
|
||||
TagPrivate() :
|
||||
file(0),
|
||||
tagOffset(0),
|
||||
track(0),
|
||||
genre(255) {}
|
||||
|
||||
File *file;
|
||||
long tagOffset;
|
||||
|
||||
String title;
|
||||
String artist;
|
||||
String album;
|
||||
String year;
|
||||
String comment;
|
||||
unsigned char track;
|
||||
unsigned char genre;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// StringHandler implementation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
StringHandler::StringHandler()
|
||||
{
|
||||
}
|
||||
|
||||
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())
|
||||
return s.data(String::Latin1);
|
||||
else
|
||||
return ByteVector();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ID3v1::Tag::Tag() :
|
||||
TagLib::Tag(),
|
||||
d(new TagPrivate())
|
||||
{
|
||||
}
|
||||
|
||||
ID3v1::Tag::Tag(File *file, long tagOffset) :
|
||||
TagLib::Tag(),
|
||||
d(new TagPrivate())
|
||||
{
|
||||
d->file = file;
|
||||
d->tagOffset = tagOffset;
|
||||
|
||||
read();
|
||||
}
|
||||
|
||||
ID3v1::Tag::~Tag()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
ByteVector ID3v1::Tag::render() const
|
||||
{
|
||||
ByteVector data;
|
||||
|
||||
data.append(fileIdentifier());
|
||||
data.append(stringHandler->render(d->title).resize(30));
|
||||
data.append(stringHandler->render(d->artist).resize(30));
|
||||
data.append(stringHandler->render(d->album).resize(30));
|
||||
data.append(stringHandler->render(d->year).resize(4));
|
||||
data.append(stringHandler->render(d->comment).resize(28));
|
||||
data.append(char(0));
|
||||
data.append(char(d->track));
|
||||
data.append(char(d->genre));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
ByteVector ID3v1::Tag::fileIdentifier()
|
||||
{
|
||||
return ByteVector::fromCString("TAG");
|
||||
}
|
||||
|
||||
String ID3v1::Tag::title() const
|
||||
{
|
||||
return d->title;
|
||||
}
|
||||
|
||||
String ID3v1::Tag::artist() const
|
||||
{
|
||||
return d->artist;
|
||||
}
|
||||
|
||||
String ID3v1::Tag::album() const
|
||||
{
|
||||
return d->album;
|
||||
}
|
||||
|
||||
String ID3v1::Tag::comment() const
|
||||
{
|
||||
return d->comment;
|
||||
}
|
||||
|
||||
String ID3v1::Tag::genre() const
|
||||
{
|
||||
return ID3v1::genre(d->genre);
|
||||
}
|
||||
|
||||
unsigned int ID3v1::Tag::year() const
|
||||
{
|
||||
return d->year.toInt();
|
||||
}
|
||||
|
||||
unsigned int ID3v1::Tag::track() const
|
||||
{
|
||||
return d->track;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setTitle(const String &s)
|
||||
{
|
||||
d->title = s;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setArtist(const String &s)
|
||||
{
|
||||
d->artist = s;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setAlbum(const String &s)
|
||||
{
|
||||
d->album = s;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setComment(const String &s)
|
||||
{
|
||||
d->comment = s;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setGenre(const String &s)
|
||||
{
|
||||
d->genre = ID3v1::genreIndex(s);
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setYear(unsigned int i)
|
||||
{
|
||||
d->year = i > 0 ? String::number(i) : String();
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setTrack(unsigned int i)
|
||||
{
|
||||
d->track = i < 256 ? i : 0;
|
||||
}
|
||||
|
||||
unsigned int ID3v1::Tag::genreNumber() const
|
||||
{
|
||||
return d->genre;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setGenreNumber(unsigned int i)
|
||||
{
|
||||
d->genre = i < 256 ? i : 255;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setStringHandler(const StringHandler *handler)
|
||||
{
|
||||
if(handler)
|
||||
stringHandler = handler;
|
||||
else
|
||||
stringHandler = &defaultStringHandler;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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"))
|
||||
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)
|
||||
{
|
||||
int offset = 3;
|
||||
|
||||
d->title = stringHandler->parse(data.mid(offset, 30));
|
||||
offset += 30;
|
||||
|
||||
d->artist = stringHandler->parse(data.mid(offset, 30));
|
||||
offset += 30;
|
||||
|
||||
d->album = stringHandler->parse(data.mid(offset, 30));
|
||||
offset += 30;
|
||||
|
||||
d->year = stringHandler->parse(data.mid(offset, 4));
|
||||
offset += 4;
|
||||
|
||||
// Check for ID3v1.1 -- Note that ID3v1 *does not* support "track zero" -- this
|
||||
// is not a bug in TagLib. Since a zeroed byte is what we would expect to
|
||||
// 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) {
|
||||
// ID3v1.1 detected
|
||||
|
||||
d->comment = stringHandler->parse(data.mid(offset, 28));
|
||||
d->track = static_cast<unsigned char>(data[offset + 29]);
|
||||
}
|
||||
else
|
||||
d->comment = data.mid(offset, 30);
|
||||
|
||||
offset += 30;
|
||||
|
||||
d->genre = static_cast<unsigned char>(data[offset]);
|
||||
}
|
||||
202
3rdparty/taglib/mpeg/id3v1/id3v1tag.h
vendored
Normal file
202
3rdparty/taglib/mpeg/id3v1/id3v1tag.h
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_ID3V1TAG_H
|
||||
#define TAGLIB_ID3V1TAG_H
|
||||
|
||||
#include "tag.h"
|
||||
#include "tbytevector.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
class File;
|
||||
|
||||
//! An ID3v1 implementation
|
||||
|
||||
namespace ID3v1 {
|
||||
|
||||
//! 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.
|
||||
*
|
||||
* However by subclassing this class and reimplementing parse() and render()
|
||||
* and setting your reimplementation as the default with
|
||||
* ID3v1::Tag::setStringHandler() you can define how you would like these
|
||||
* transformations to be done.
|
||||
*
|
||||
* \warning It is advisable <b>not</b> to write non-ISO-8859-1 data to ID3v1
|
||||
* tags. Please consider disabling the writing of ID3v1 tags in the case
|
||||
* that the data is not ISO-8859-1.
|
||||
*
|
||||
* \see ID3v1::Tag::setStringHandler()
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
/*!
|
||||
* 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.
|
||||
*
|
||||
* \warning It is recommended that you <b>not</b> override this method, but
|
||||
* 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;
|
||||
};
|
||||
|
||||
//! 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
|
||||
* fields that it provides, the generic TagLib::Tag API is a mirror of what is
|
||||
* provided by ID3v1.
|
||||
*
|
||||
* ID3v1 tags should generally only contain Latin1 information. However because
|
||||
* many applications do not follow this rule there is now support for overriding
|
||||
* the ID3v1 string handling using the ID3v1::StringHandler class. Please see
|
||||
* the documentation for that class for more information.
|
||||
*
|
||||
* \see StringHandler
|
||||
*
|
||||
* \note Most fields are truncated to a maximum of 28-30 bytes. The
|
||||
* truncation happens automatically when the tag is rendered.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT Tag : public TagLib::Tag
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* Create an ID3v1 tag with default values.
|
||||
*/
|
||||
Tag();
|
||||
|
||||
/*!
|
||||
* Create an ID3v1 tag and parse the data in \a file starting at
|
||||
* \a tagOffset.
|
||||
*/
|
||||
Tag(File *file, long tagOffset);
|
||||
|
||||
/*!
|
||||
* Destroys this Tag instance.
|
||||
*/
|
||||
virtual ~Tag();
|
||||
|
||||
/*!
|
||||
* Renders the in memory values to a ByteVector suitable for writing to
|
||||
* the file.
|
||||
*/
|
||||
ByteVector render() const;
|
||||
|
||||
/*!
|
||||
* Returns the string "TAG" suitable for usage in locating the tag in a
|
||||
* file.
|
||||
*/
|
||||
static ByteVector fileIdentifier();
|
||||
|
||||
// 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 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;
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* 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
|
||||
* released and default ISO-8859-1 handler is restored.
|
||||
*
|
||||
* \note The caller is responsible for deleting the previous handler
|
||||
* as needed after it is released.
|
||||
*
|
||||
* \see StringHandler
|
||||
*/
|
||||
static void setStringHandler(const StringHandler *handler);
|
||||
|
||||
protected:
|
||||
/*!
|
||||
* Reads from the file specified in the constructor.
|
||||
*/
|
||||
void read();
|
||||
/*!
|
||||
* Pareses the body of the tag in \a data.
|
||||
*/
|
||||
void parse(const ByteVector &data);
|
||||
|
||||
private:
|
||||
Tag(const Tag &);
|
||||
Tag &operator=(const Tag &);
|
||||
|
||||
class TagPrivate;
|
||||
TagPrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
225
3rdparty/taglib/mpeg/id3v2/frames/attachedpictureframe.cpp
vendored
Normal file
225
3rdparty/taglib/mpeg/id3v2/frames/attachedpictureframe.cpp
vendored
Normal file
@@ -0,0 +1,225 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include "attachedpictureframe.h"
|
||||
|
||||
#include <tstringlist.h>
|
||||
#include <tdebug.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class AttachedPictureFrame::AttachedPictureFramePrivate
|
||||
{
|
||||
public:
|
||||
AttachedPictureFramePrivate() : textEncoding(String::Latin1),
|
||||
type(AttachedPictureFrame::Other) {}
|
||||
|
||||
String::Type textEncoding;
|
||||
String mimeType;
|
||||
AttachedPictureFrame::Type type;
|
||||
String description;
|
||||
ByteVector data;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AttachedPictureFrame::AttachedPictureFrame() :
|
||||
Frame("APIC"),
|
||||
d(new AttachedPictureFramePrivate())
|
||||
{
|
||||
}
|
||||
|
||||
AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data) :
|
||||
Frame(data),
|
||||
d(new AttachedPictureFramePrivate())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
|
||||
AttachedPictureFrame::~AttachedPictureFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String AttachedPictureFrame::toString() const
|
||||
{
|
||||
String s = "[" + d->mimeType + "]";
|
||||
return d->description.isEmpty() ? s : d->description + " " + s;
|
||||
}
|
||||
|
||||
String::Type AttachedPictureFrame::textEncoding() const
|
||||
{
|
||||
return d->textEncoding;
|
||||
}
|
||||
|
||||
void AttachedPictureFrame::setTextEncoding(String::Type t)
|
||||
{
|
||||
d->textEncoding = t;
|
||||
}
|
||||
|
||||
String AttachedPictureFrame::mimeType() const
|
||||
{
|
||||
return d->mimeType;
|
||||
}
|
||||
|
||||
void AttachedPictureFrame::setMimeType(const String &m)
|
||||
{
|
||||
d->mimeType = m;
|
||||
}
|
||||
|
||||
AttachedPictureFrame::Type AttachedPictureFrame::type() const
|
||||
{
|
||||
return d->type;
|
||||
}
|
||||
|
||||
void AttachedPictureFrame::setType(Type t)
|
||||
{
|
||||
d->type = t;
|
||||
}
|
||||
|
||||
String AttachedPictureFrame::description() const
|
||||
{
|
||||
return d->description;
|
||||
}
|
||||
|
||||
void AttachedPictureFrame::setDescription(const String &desc)
|
||||
{
|
||||
d->description = desc;
|
||||
}
|
||||
|
||||
ByteVector AttachedPictureFrame::picture() const
|
||||
{
|
||||
return d->data;
|
||||
}
|
||||
|
||||
void AttachedPictureFrame::setPicture(const ByteVector &p)
|
||||
{
|
||||
d->data = p;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AttachedPictureFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
if(data.size() < 5) {
|
||||
debug("A picture frame must contain at least 5 bytes.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->textEncoding = String::Type(data[0]);
|
||||
|
||||
int pos = 1;
|
||||
|
||||
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()) {
|
||||
debug("Truncated picture frame.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->type = (TagLib::ID3v2::AttachedPictureFrame::Type)data[pos++];
|
||||
d->description = readStringField(data, d->textEncoding, &pos);
|
||||
|
||||
d->data = data.mid(pos);
|
||||
}
|
||||
|
||||
ByteVector AttachedPictureFrame::renderFields() const
|
||||
{
|
||||
ByteVector data;
|
||||
|
||||
String::Type encoding = checkTextEncoding(d->description, d->textEncoding);
|
||||
|
||||
data.append(char(encoding));
|
||||
data.append(d->mimeType.data(String::Latin1));
|
||||
data.append(textDelimiter(String::Latin1));
|
||||
data.append(char(d->type));
|
||||
data.append(d->description.data(encoding));
|
||||
data.append(textDelimiter(encoding));
|
||||
data.append(d->data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new AttachedPictureFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// support for ID3v2.2 PIC frames
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AttachedPictureFrameV22::parseFields(const ByteVector &data)
|
||||
{
|
||||
if(data.size() < 5) {
|
||||
debug("A picture frame must contain at least 5 bytes.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->textEncoding = String::Type(data[0]);
|
||||
|
||||
int pos = 1;
|
||||
|
||||
String fixedString = String(data.mid(pos, 3), String::Latin1);
|
||||
pos += 3;
|
||||
// convert fixed string image type to mime string
|
||||
if (fixedString.upper() == "JPG") {
|
||||
d->mimeType = "image/jpeg";
|
||||
} else if (fixedString.upper() == "PNG") {
|
||||
d->mimeType = "image/png";
|
||||
} else {
|
||||
debug("probably unsupported image type");
|
||||
d->mimeType = "image/" + fixedString;
|
||||
}
|
||||
|
||||
d->type = (TagLib::ID3v2::AttachedPictureFrame::Type)data[pos++];
|
||||
d->description = readStringField(data, d->textEncoding, &pos);
|
||||
|
||||
d->data = data.mid(pos);
|
||||
}
|
||||
|
||||
AttachedPictureFrameV22::AttachedPictureFrameV22(const ByteVector &data, Header *h)
|
||||
{
|
||||
// set v2.2 header to make fieldData work correctly
|
||||
setHeader(h, true);
|
||||
|
||||
parseFields(fieldData(data));
|
||||
|
||||
// now set the v2.4 header
|
||||
Frame::Header *newHeader = new Frame::Header("APIC");
|
||||
newHeader->setFrameSize(h->frameSize());
|
||||
setHeader(newHeader, true);
|
||||
}
|
||||
230
3rdparty/taglib/mpeg/id3v2/frames/attachedpictureframe.h
vendored
Normal file
230
3rdparty/taglib/mpeg/id3v2/frames/attachedpictureframe.h
vendored
Normal file
@@ -0,0 +1,230 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_ATTACHEDPICTUREFRAME_H
|
||||
#define TAGLIB_ATTACHEDPICTUREFRAME_H
|
||||
|
||||
#include "id3v2frame.h"
|
||||
#include "id3v2header.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! 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;
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
/*!
|
||||
* Constructs an empty picture frame. The description, content and text
|
||||
* encoding should be set manually.
|
||||
*/
|
||||
AttachedPictureFrame();
|
||||
|
||||
/*!
|
||||
* Constructs an AttachedPicture frame based on \a data.
|
||||
*/
|
||||
explicit AttachedPictureFrame(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Destroys the AttahcedPictureFrame instance.
|
||||
*/
|
||||
virtual ~AttachedPictureFrame();
|
||||
|
||||
/*!
|
||||
* Returns a string containing the description and mime-type
|
||||
*/
|
||||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
* Returns the text encoding used for the description.
|
||||
*
|
||||
* \see setTextEncoding()
|
||||
* \see description()
|
||||
*/
|
||||
String::Type textEncoding() const;
|
||||
|
||||
/*!
|
||||
* Set the text encoding used for the description.
|
||||
*
|
||||
* \see description()
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Sets the mime type of the image. This should in most cases be
|
||||
* "image/png" or "image/jpeg".
|
||||
*/
|
||||
void setMimeType(const String &m);
|
||||
|
||||
/*!
|
||||
* Returns the type of the image.
|
||||
*
|
||||
* \see Type
|
||||
* \see setType()
|
||||
*/
|
||||
Type type() const;
|
||||
|
||||
/*!
|
||||
* Sets the type for the image.
|
||||
*
|
||||
* \see Type
|
||||
* \see type()
|
||||
*/
|
||||
void setType(Type t);
|
||||
|
||||
/*!
|
||||
* Returns a text description of the image.
|
||||
*
|
||||
* \see setDescription()
|
||||
* \see textEncoding()
|
||||
* \see setTextEncoding()
|
||||
*/
|
||||
|
||||
String description() const;
|
||||
|
||||
/*!
|
||||
* Sets a textual description of the image to \a desc.
|
||||
*
|
||||
* \see description()
|
||||
* \see textEncoding()
|
||||
* \see setTextEncoding()
|
||||
*/
|
||||
|
||||
void setDescription(const String &desc);
|
||||
|
||||
/*!
|
||||
* Returns the image data as a ByteVector.
|
||||
*
|
||||
* \note ByteVector has a data() method that returns a const char * which
|
||||
* should make it easy to export this data to external programs.
|
||||
*
|
||||
* \see setPicture()
|
||||
* \see mimeType()
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* \see picture()
|
||||
* \see mimeType()
|
||||
* \see setMimeType()
|
||||
*/
|
||||
void setPicture(const ByteVector &p);
|
||||
|
||||
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);
|
||||
|
||||
};
|
||||
|
||||
//! 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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
309
3rdparty/taglib/mpeg/id3v2/frames/chapterframe.cpp
vendored
Normal file
309
3rdparty/taglib/mpeg/id3v2/frames/chapterframe.cpp
vendored
Normal file
@@ -0,0 +1,309 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2013 by Lukas Krejci
|
||||
email : krejclu6@fel.cvut.cz
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tbytevectorlist.h>
|
||||
#include <tpropertymap.h>
|
||||
#include <tdebug.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "chapterframe.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class ChapterFrame::ChapterFramePrivate
|
||||
{
|
||||
public:
|
||||
ChapterFramePrivate() :
|
||||
tagHeader(0),
|
||||
startTime(0),
|
||||
endTime(0),
|
||||
startOffset(0),
|
||||
endOffset(0)
|
||||
{
|
||||
embeddedFrameList.setAutoDelete(true);
|
||||
}
|
||||
|
||||
const ID3v2::Header *tagHeader;
|
||||
ByteVector elementID;
|
||||
unsigned int startTime;
|
||||
unsigned int endTime;
|
||||
unsigned int startOffset;
|
||||
unsigned int endOffset;
|
||||
FrameListMap embeddedFrameListMap;
|
||||
FrameList embeddedFrameList;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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())
|
||||
{
|
||||
// setElementID has a workaround for a previously silly API where you had to
|
||||
// specifically include the null byte.
|
||||
|
||||
setElementID(elementID);
|
||||
|
||||
d->startTime = startTime;
|
||||
d->endTime = endTime;
|
||||
d->startOffset = startOffset;
|
||||
d->endOffset = endOffset;
|
||||
|
||||
for(FrameList::ConstIterator it = embeddedFrames.begin();
|
||||
it != embeddedFrames.end(); ++it)
|
||||
addEmbeddedFrame(*it);
|
||||
}
|
||||
|
||||
ChapterFrame::~ChapterFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
ByteVector ChapterFrame::elementID() const
|
||||
{
|
||||
return d->elementID;
|
||||
}
|
||||
|
||||
unsigned int ChapterFrame::startTime() const
|
||||
{
|
||||
return d->startTime;
|
||||
}
|
||||
|
||||
unsigned int ChapterFrame::endTime() const
|
||||
{
|
||||
return d->endTime;
|
||||
}
|
||||
|
||||
unsigned int ChapterFrame::startOffset() const
|
||||
{
|
||||
return d->startOffset;
|
||||
}
|
||||
|
||||
unsigned int ChapterFrame::endOffset() const
|
||||
{
|
||||
return d->endOffset;
|
||||
}
|
||||
|
||||
void ChapterFrame::setElementID(const ByteVector &eID)
|
||||
{
|
||||
d->elementID = eID;
|
||||
|
||||
if(d->elementID.endsWith(char(0)))
|
||||
d->elementID = d->elementID.mid(0, d->elementID.size() - 1);
|
||||
}
|
||||
|
||||
void ChapterFrame::setStartTime(const unsigned int &sT)
|
||||
{
|
||||
d->startTime = sT;
|
||||
}
|
||||
|
||||
void ChapterFrame::setEndTime(const unsigned int &eT)
|
||||
{
|
||||
d->endTime = eT;
|
||||
}
|
||||
|
||||
void ChapterFrame::setStartOffset(const unsigned int &sO)
|
||||
{
|
||||
d->startOffset = sO;
|
||||
}
|
||||
|
||||
void ChapterFrame::setEndOffset(const unsigned int &eO)
|
||||
{
|
||||
d->endOffset = eO;
|
||||
}
|
||||
|
||||
const FrameListMap &ChapterFrame::embeddedFrameListMap() const
|
||||
{
|
||||
return d->embeddedFrameListMap;
|
||||
}
|
||||
|
||||
const FrameList &ChapterFrame::embeddedFrameList() const
|
||||
{
|
||||
return d->embeddedFrameList;
|
||||
}
|
||||
|
||||
const FrameList &ChapterFrame::embeddedFrameList(const ByteVector &frameID) const
|
||||
{
|
||||
return d->embeddedFrameListMap[frameID];
|
||||
}
|
||||
|
||||
void ChapterFrame::addEmbeddedFrame(Frame *frame)
|
||||
{
|
||||
d->embeddedFrameList.append(frame);
|
||||
d->embeddedFrameListMap[frame->frameID()].append(frame);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// ...and from the frame list map
|
||||
it = d->embeddedFrameListMap[frame->frameID()].find(frame);
|
||||
d->embeddedFrameListMap[frame->frameID()].erase(it);
|
||||
|
||||
// ...and delete as desired
|
||||
if(del)
|
||||
delete frame;
|
||||
}
|
||||
|
||||
void ChapterFrame::removeEmbeddedFrames(const ByteVector &id)
|
||||
{
|
||||
FrameList l = d->embeddedFrameListMap[id];
|
||||
for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
|
||||
removeEmbeddedFrame(*it, true);
|
||||
}
|
||||
|
||||
String ChapterFrame::toString() const
|
||||
{
|
||||
String s = String(d->elementID) +
|
||||
": start time: " + String::number(d->startTime) +
|
||||
", end time: " + String::number(d->endTime);
|
||||
|
||||
if(d->startOffset != 0xFFFFFFFF)
|
||||
s += ", start offset: " + String::number(d->startOffset);
|
||||
|
||||
if(d->endOffset != 0xFFFFFFFF)
|
||||
s += ", end offset: " + String::number(d->endOffset);
|
||||
|
||||
if(!d->embeddedFrameList.isEmpty()) {
|
||||
StringList frameIDs;
|
||||
for(FrameList::ConstIterator it = d->embeddedFrameList.begin();
|
||||
it != d->embeddedFrameList.end(); ++it)
|
||||
frameIDs.append((*it)->frameID());
|
||||
s += ", sub-frames: [ " + frameIDs.toString(", ") + " ]";
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
PropertyMap ChapterFrame::asProperties() const
|
||||
{
|
||||
PropertyMap map;
|
||||
|
||||
map.unsupportedData().append(frameID() + String("/") + d->elementID);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
ChapterFrame *frame = dynamic_cast<ChapterFrame *>(*it);
|
||||
if(frame && frame->elementID() == eID)
|
||||
return frame;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ChapterFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
unsigned int size = data.size();
|
||||
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;
|
||||
}
|
||||
|
||||
int pos = 0;
|
||||
unsigned int embPos = 0;
|
||||
d->elementID = readStringField(data, String::Latin1, &pos).data(String::Latin1);
|
||||
d->startTime = data.toUInt(pos, true);
|
||||
pos += 4;
|
||||
d->endTime = data.toUInt(pos, true);
|
||||
pos += 4;
|
||||
d->startOffset = data.toUInt(pos, true);
|
||||
pos += 4;
|
||||
d->endOffset = data.toUInt(pos, true);
|
||||
pos += 4;
|
||||
size -= pos;
|
||||
|
||||
// Embedded frames are optional
|
||||
|
||||
if(size < header()->size())
|
||||
return;
|
||||
|
||||
while(embPos < size - header()->size()) {
|
||||
Frame *frame = FrameFactory::instance()->createFrame(data.mid(pos + embPos), (d->tagHeader != 0));
|
||||
|
||||
if(!frame)
|
||||
return;
|
||||
|
||||
// Checks to make sure that frame parsed correctly.
|
||||
if(frame->size() <= 0) {
|
||||
delete frame;
|
||||
return;
|
||||
}
|
||||
|
||||
embPos += frame->size() + header()->size();
|
||||
addEmbeddedFrame(frame);
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector ChapterFrame::renderFields() const
|
||||
{
|
||||
ByteVector data;
|
||||
|
||||
data.append(d->elementID);
|
||||
data.append('\0');
|
||||
data.append(ByteVector::fromUInt(d->startTime, true));
|
||||
data.append(ByteVector::fromUInt(d->endTime, true));
|
||||
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)
|
||||
data.append((*it)->render());
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new ChapterFramePrivate())
|
||||
{
|
||||
d->tagHeader = tagHeader;
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
249
3rdparty/taglib/mpeg/id3v2/frames/chapterframe.h
vendored
Normal file
249
3rdparty/taglib/mpeg/id3v2/frames/chapterframe.h
vendored
Normal file
@@ -0,0 +1,249 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2013 by Lukas Krejci
|
||||
email : krejclu6@fel.cvut.cz
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_CHAPTERFRAME
|
||||
#define TAGLIB_CHAPTERFRAME
|
||||
|
||||
#include "id3v2tag.h"
|
||||
#include "id3v2frame.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
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
|
||||
|
||||
class TAGLIB_EXPORT ChapterFrame : public ID3v2::Frame
|
||||
{
|
||||
friend class FrameFactory;
|
||||
|
||||
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);
|
||||
|
||||
/*!
|
||||
* 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,
|
||||
* whose ownership will then be taken over by this Frame, in
|
||||
* \a embeededFrames;
|
||||
*
|
||||
* 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());
|
||||
|
||||
/*!
|
||||
* Destroys the frame.
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Returns time of chapter's start (in milliseconds).
|
||||
*
|
||||
* \see setStartTime()
|
||||
*/
|
||||
unsigned int startTime() const;
|
||||
|
||||
/*!
|
||||
* Returns time of chapter's end (in milliseconds).
|
||||
*
|
||||
* \see setEndTime()
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* 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;
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* Sets time of chapter's start (in milliseconds) to \a sT.
|
||||
*
|
||||
* \see startTime()
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* Returns a reference to the frame list map. This is an FrameListMap of
|
||||
* all of the frames embedded in the CHAP frame.
|
||||
*
|
||||
* This is the most convenient structure for accessing the CHAP frame's
|
||||
* embedded frames. Many frame types allow multiple instances of the same
|
||||
* frame type so this is a map of lists. In most cases however there will
|
||||
* only be a single frame of a certain type.
|
||||
*
|
||||
* \warning You should not modify this data structure directly, instead
|
||||
* use addEmbeddedFrame() and removeEmbeddedFrame().
|
||||
*
|
||||
* \see embeddedFrameList()
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* This can be useful if for example you want iterate over the CHAP frame's
|
||||
* embedded frames in the order that they occur in the CHAP frame.
|
||||
*
|
||||
* \warning You should not modify this data structure directly, instead
|
||||
* use addEmbeddedFrame() and removeEmbeddedFrame().
|
||||
*/
|
||||
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:
|
||||
*
|
||||
* \code
|
||||
* embeddedFrameListMap()[frameID];
|
||||
* \endcode
|
||||
*
|
||||
* \see embeddedFrameListMap()
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
virtual String toString() 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);
|
||||
|
||||
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 &);
|
||||
|
||||
class ChapterFramePrivate;
|
||||
ChapterFramePrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
198
3rdparty/taglib/mpeg/id3v2/frames/commentsframe.cpp
vendored
Normal file
198
3rdparty/taglib/mpeg/id3v2/frames/commentsframe.cpp
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tbytevectorlist.h>
|
||||
#include <id3v2tag.h>
|
||||
#include <tdebug.h>
|
||||
#include <tstringlist.h>
|
||||
|
||||
#include "commentsframe.h"
|
||||
#include "tpropertymap.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class CommentsFrame::CommentsFramePrivate
|
||||
{
|
||||
public:
|
||||
CommentsFramePrivate() : textEncoding(String::Latin1) {}
|
||||
String::Type textEncoding;
|
||||
ByteVector language;
|
||||
String description;
|
||||
String text;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CommentsFrame::CommentsFrame(String::Type encoding) :
|
||||
Frame("COMM"),
|
||||
d(new CommentsFramePrivate())
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
CommentsFrame::CommentsFrame(const ByteVector &data) :
|
||||
Frame(data),
|
||||
d(new CommentsFramePrivate())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
|
||||
CommentsFrame::~CommentsFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String CommentsFrame::toString() const
|
||||
{
|
||||
return d->text;
|
||||
}
|
||||
|
||||
ByteVector CommentsFrame::language() const
|
||||
{
|
||||
return d->language;
|
||||
}
|
||||
|
||||
String CommentsFrame::description() const
|
||||
{
|
||||
return d->description;
|
||||
}
|
||||
|
||||
String CommentsFrame::text() const
|
||||
{
|
||||
return d->text;
|
||||
}
|
||||
|
||||
void CommentsFrame::setLanguage(const ByteVector &languageEncoding)
|
||||
{
|
||||
d->language = languageEncoding.mid(0, 3);
|
||||
}
|
||||
|
||||
void CommentsFrame::setDescription(const String &s)
|
||||
{
|
||||
d->description = s;
|
||||
}
|
||||
|
||||
void CommentsFrame::setText(const String &s)
|
||||
{
|
||||
d->text = s;
|
||||
}
|
||||
|
||||
String::Type CommentsFrame::textEncoding() const
|
||||
{
|
||||
return d->textEncoding;
|
||||
}
|
||||
|
||||
void CommentsFrame::setTextEncoding(String::Type encoding)
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
PropertyMap CommentsFrame::asProperties() const
|
||||
{
|
||||
String key = description().upper();
|
||||
PropertyMap map;
|
||||
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
|
||||
{
|
||||
ID3v2::FrameList comments = tag->frameList("COMM");
|
||||
|
||||
for(ID3v2::FrameList::ConstIterator it = comments.begin();
|
||||
it != comments.end();
|
||||
++it)
|
||||
{
|
||||
CommentsFrame *frame = dynamic_cast<CommentsFrame *>(*it);
|
||||
if(frame && frame->description() == d)
|
||||
return frame;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CommentsFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
if(data.size() < 5) {
|
||||
debug("A comment frame must contain at least 5 bytes.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->textEncoding = String::Type(data[0]);
|
||||
d->language = data.mid(1, 3);
|
||||
|
||||
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) {
|
||||
d->description = Tag::latin1StringHandler()->parse(l.front());
|
||||
d->text = Tag::latin1StringHandler()->parse(l.back());
|
||||
} else {
|
||||
d->description = String(l.front(), d->textEncoding);
|
||||
d->text = String(l.back(), d->textEncoding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector CommentsFrame::renderFields() const
|
||||
{
|
||||
ByteVector v;
|
||||
|
||||
String::Type encoding = d->textEncoding;
|
||||
|
||||
encoding = checkTextEncoding(d->description, encoding);
|
||||
encoding = checkTextEncoding(d->text, encoding);
|
||||
|
||||
v.append(char(encoding));
|
||||
v.append(d->language.size() == 3 ? d->language : "XXX");
|
||||
v.append(d->description.data(encoding));
|
||||
v.append(textDelimiter(encoding));
|
||||
v.append(d->text.data(encoding));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CommentsFrame::CommentsFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new CommentsFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
179
3rdparty/taglib/mpeg/id3v2/frames/commentsframe.h
vendored
Normal file
179
3rdparty/taglib/mpeg/id3v2/frames/commentsframe.h
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_COMMENTSFRAME_H
|
||||
#define TAGLIB_COMMENTSFRAME_H
|
||||
|
||||
#include "id3v2frame.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! 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;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Construct an empty comment frame that will use the text encoding
|
||||
* \a encoding.
|
||||
*/
|
||||
explicit CommentsFrame(String::Type encoding = String::Latin1);
|
||||
|
||||
/*!
|
||||
* Construct a comment based on the data in \a data.
|
||||
*/
|
||||
explicit CommentsFrame(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Destroys this CommentFrame instance.
|
||||
*/
|
||||
virtual ~CommentsFrame();
|
||||
|
||||
/*!
|
||||
* Returns the text of this comment.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
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>.
|
||||
*
|
||||
* \note Most taggers simply ignore this value.
|
||||
*
|
||||
* \see setLanguage()
|
||||
*/
|
||||
ByteVector language() const;
|
||||
|
||||
/*!
|
||||
* Returns the description of this comment.
|
||||
*
|
||||
* \note Most taggers simply ignore this value.
|
||||
*
|
||||
* \see setDescription()
|
||||
*/
|
||||
String description() const;
|
||||
|
||||
/*!
|
||||
* Returns the text of this comment.
|
||||
*
|
||||
* \see setText()
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* Sets the description of the comment to \a s.
|
||||
*
|
||||
* \see description()
|
||||
*/
|
||||
void setDescription(const String &s);
|
||||
|
||||
/*!
|
||||
* Sets the text portion of the comment to \a s.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* \see setTextEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* 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
|
||||
* marked unsupported by an entry "COMM/<description>" in the unsupportedData()
|
||||
* attribute of the returned map.
|
||||
* - otherwise, the key will be "COMMENT:<description>"
|
||||
* - The single value will be the frame's text().
|
||||
*/
|
||||
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);
|
||||
|
||||
protected:
|
||||
// Reimplementations.
|
||||
|
||||
virtual void parseFields(const ByteVector &data);
|
||||
virtual ByteVector renderFields() const;
|
||||
|
||||
private:
|
||||
/*!
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
CommentsFrame(const ByteVector &data, Header *h);
|
||||
CommentsFrame(const CommentsFrame &);
|
||||
CommentsFrame &operator=(const CommentsFrame &);
|
||||
|
||||
class CommentsFramePrivate;
|
||||
CommentsFramePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
144
3rdparty/taglib/mpeg/id3v2/frames/eventtimingcodesframe.cpp
vendored
Normal file
144
3rdparty/taglib/mpeg/id3v2/frames/eventtimingcodesframe.cpp
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2014 by Urs Fleisch
|
||||
email : ufleisch@users.sourceforge.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include "eventtimingcodesframe.h"
|
||||
#include <tbytevectorlist.h>
|
||||
#include <id3v2tag.h>
|
||||
#include <tdebug.h>
|
||||
#include <tpropertymap.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class EventTimingCodesFrame::EventTimingCodesFramePrivate
|
||||
{
|
||||
public:
|
||||
EventTimingCodesFramePrivate() :
|
||||
timestampFormat(EventTimingCodesFrame::AbsoluteMilliseconds) {}
|
||||
EventTimingCodesFrame::TimestampFormat timestampFormat;
|
||||
EventTimingCodesFrame::SynchedEventList synchedEvents;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EventTimingCodesFrame::EventTimingCodesFrame() :
|
||||
Frame("ETCO"),
|
||||
d(new EventTimingCodesFramePrivate())
|
||||
{
|
||||
}
|
||||
|
||||
EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data) :
|
||||
Frame(data),
|
||||
d(new EventTimingCodesFramePrivate())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
|
||||
EventTimingCodesFrame::~EventTimingCodesFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String EventTimingCodesFrame::toString() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
EventTimingCodesFrame::TimestampFormat
|
||||
EventTimingCodesFrame::timestampFormat() const
|
||||
{
|
||||
return d->timestampFormat;
|
||||
}
|
||||
|
||||
EventTimingCodesFrame::SynchedEventList
|
||||
EventTimingCodesFrame::synchedEvents() const
|
||||
{
|
||||
return d->synchedEvents;
|
||||
}
|
||||
|
||||
void EventTimingCodesFrame::setTimestampFormat(
|
||||
EventTimingCodesFrame::TimestampFormat f)
|
||||
{
|
||||
d->timestampFormat = f;
|
||||
}
|
||||
|
||||
void EventTimingCodesFrame::setSynchedEvents(
|
||||
const EventTimingCodesFrame::SynchedEventList &e)
|
||||
{
|
||||
d->synchedEvents = e;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void EventTimingCodesFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
const int end = data.size();
|
||||
if(end < 1) {
|
||||
debug("An event timing codes frame must contain at least 1 byte.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->timestampFormat = TimestampFormat(data[0]);
|
||||
|
||||
int pos = 1;
|
||||
d->synchedEvents.clear();
|
||||
while(pos + 4 < end) {
|
||||
EventType type = static_cast<EventType>(static_cast<unsigned char>(data[pos++]));
|
||||
unsigned int time = data.toUInt(pos, true);
|
||||
pos += 4;
|
||||
d->synchedEvents.append(SynchedEvent(time, type));
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector EventTimingCodesFrame::renderFields() const
|
||||
{
|
||||
ByteVector v;
|
||||
|
||||
v.append(char(d->timestampFormat));
|
||||
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));
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new EventTimingCodesFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
185
3rdparty/taglib/mpeg/id3v2/frames/eventtimingcodesframe.h
vendored
Normal file
185
3rdparty/taglib/mpeg/id3v2/frames/eventtimingcodesframe.h
vendored
Normal file
@@ -0,0 +1,185 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2014 by Urs Fleisch
|
||||
email : ufleisch@users.sourceforge.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_EVENTTIMINGCODESFRAME_H
|
||||
#define TAGLIB_EVENTTIMINGCODESFRAME_H
|
||||
|
||||
#include "id3v2frame.h"
|
||||
#include "tlist.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! ID3v2 event timing codes frame
|
||||
/*!
|
||||
* An implementation of ID3v2 event timing codes.
|
||||
*/
|
||||
class TAGLIB_EXPORT EventTimingCodesFrame : public Frame
|
||||
{
|
||||
friend class FrameFactory;
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
/*!
|
||||
* 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
|
||||
};
|
||||
|
||||
/*!
|
||||
* Single entry of time stamp and event.
|
||||
*/
|
||||
struct SynchedEvent {
|
||||
SynchedEvent(unsigned int ms, EventType t) : time(ms), type(t) {}
|
||||
unsigned int time;
|
||||
EventType type;
|
||||
};
|
||||
|
||||
/*!
|
||||
* List of synchronized events.
|
||||
*/
|
||||
typedef TagLib::List<SynchedEvent> SynchedEventList;
|
||||
|
||||
/*!
|
||||
* Construct an empty event timing codes frame.
|
||||
*/
|
||||
explicit EventTimingCodesFrame();
|
||||
|
||||
/*!
|
||||
* Construct a event timing codes frame based on the data in \a data.
|
||||
*/
|
||||
explicit EventTimingCodesFrame(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Destroys this EventTimingCodesFrame instance.
|
||||
*/
|
||||
virtual ~EventTimingCodesFrame();
|
||||
|
||||
/*!
|
||||
* Returns a null string.
|
||||
*/
|
||||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
* Returns the timestamp format.
|
||||
*/
|
||||
TimestampFormat timestampFormat() const;
|
||||
|
||||
/*!
|
||||
* Returns the events with the time stamps.
|
||||
*/
|
||||
SynchedEventList synchedEvents() const;
|
||||
|
||||
/*!
|
||||
* Set the timestamp format.
|
||||
*
|
||||
* \see timestampFormat()
|
||||
*/
|
||||
void setTimestampFormat(TimestampFormat f);
|
||||
|
||||
/*!
|
||||
* Sets the text with the time stamps.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
void setSynchedEvents(const SynchedEventList &e);
|
||||
|
||||
protected:
|
||||
// Reimplementations.
|
||||
|
||||
virtual void parseFields(const ByteVector &data);
|
||||
virtual ByteVector renderFields() const;
|
||||
|
||||
private:
|
||||
/*!
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
EventTimingCodesFrame(const ByteVector &data, Header *h);
|
||||
EventTimingCodesFrame(const EventTimingCodesFrame &);
|
||||
EventTimingCodesFrame &operator=(const EventTimingCodesFrame &);
|
||||
|
||||
class EventTimingCodesFramePrivate;
|
||||
EventTimingCodesFramePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
187
3rdparty/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp
vendored
Normal file
187
3rdparty/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
|
||||
copyright : (C) 2006 by Aaron VonderHaar
|
||||
email : avh4@users.sourceforge.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tdebug.h>
|
||||
#include <tstringlist.h>
|
||||
|
||||
#include "generalencapsulatedobjectframe.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFramePrivate
|
||||
{
|
||||
public:
|
||||
GeneralEncapsulatedObjectFramePrivate() : textEncoding(String::Latin1) {}
|
||||
|
||||
String::Type textEncoding;
|
||||
String mimeType;
|
||||
String fileName;
|
||||
String description;
|
||||
ByteVector data;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame() :
|
||||
Frame("GEOB"),
|
||||
d(new GeneralEncapsulatedObjectFramePrivate())
|
||||
{
|
||||
}
|
||||
|
||||
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data) :
|
||||
Frame(data),
|
||||
d(new GeneralEncapsulatedObjectFramePrivate())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
|
||||
GeneralEncapsulatedObjectFrame::~GeneralEncapsulatedObjectFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String GeneralEncapsulatedObjectFrame::toString() const
|
||||
{
|
||||
String text = "[" + d->mimeType + "]";
|
||||
|
||||
if(!d->fileName.isEmpty())
|
||||
text += " " + d->fileName;
|
||||
|
||||
if(!d->description.isEmpty())
|
||||
text += " \"" + d->description + "\"";
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
String::Type GeneralEncapsulatedObjectFrame::textEncoding() const
|
||||
{
|
||||
return d->textEncoding;
|
||||
}
|
||||
|
||||
void GeneralEncapsulatedObjectFrame::setTextEncoding(String::Type encoding)
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
String GeneralEncapsulatedObjectFrame::mimeType() const
|
||||
{
|
||||
return d->mimeType;
|
||||
}
|
||||
|
||||
void GeneralEncapsulatedObjectFrame::setMimeType(const String &type)
|
||||
{
|
||||
d->mimeType = type;
|
||||
}
|
||||
|
||||
String GeneralEncapsulatedObjectFrame::fileName() const
|
||||
{
|
||||
return d->fileName;
|
||||
}
|
||||
|
||||
void GeneralEncapsulatedObjectFrame::setFileName(const String &name)
|
||||
{
|
||||
d->fileName = name;
|
||||
}
|
||||
|
||||
String GeneralEncapsulatedObjectFrame::description() const
|
||||
{
|
||||
return d->description;
|
||||
}
|
||||
|
||||
void GeneralEncapsulatedObjectFrame::setDescription(const String &desc)
|
||||
{
|
||||
d->description = desc;
|
||||
}
|
||||
|
||||
ByteVector GeneralEncapsulatedObjectFrame::object() const
|
||||
{
|
||||
return d->data;
|
||||
}
|
||||
|
||||
void GeneralEncapsulatedObjectFrame::setObject(const ByteVector &data)
|
||||
{
|
||||
d->data = data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void GeneralEncapsulatedObjectFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
if(data.size() < 4) {
|
||||
debug("An object frame must contain at least 4 bytes.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->textEncoding = String::Type(data[0]);
|
||||
|
||||
int pos = 1;
|
||||
|
||||
d->mimeType = readStringField(data, String::Latin1, &pos);
|
||||
d->fileName = readStringField(data, d->textEncoding, &pos);
|
||||
d->description = readStringField(data, d->textEncoding, &pos);
|
||||
|
||||
d->data = data.mid(pos);
|
||||
}
|
||||
|
||||
ByteVector GeneralEncapsulatedObjectFrame::renderFields() const
|
||||
{
|
||||
StringList sl;
|
||||
sl.append(d->fileName);
|
||||
sl.append(d->description);
|
||||
|
||||
const String::Type encoding = checkTextEncoding(sl, d->textEncoding);
|
||||
|
||||
ByteVector data;
|
||||
|
||||
data.append(char(encoding));
|
||||
data.append(d->mimeType.data(String::Latin1));
|
||||
data.append(textDelimiter(String::Latin1));
|
||||
data.append(d->fileName.data(encoding));
|
||||
data.append(textDelimiter(encoding));
|
||||
data.append(d->description.data(encoding));
|
||||
data.append(textDelimiter(encoding));
|
||||
data.append(d->data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new GeneralEncapsulatedObjectFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
179
3rdparty/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.h
vendored
Normal file
179
3rdparty/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.h
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
|
||||
copyright : (C) 2006 by Aaron VonderHaar
|
||||
email : avh4@users.sourceforge.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_GENERALENCAPSULATEDOBJECT_H
|
||||
#define TAGLIB_GENERALENCAPSULATEDOBJECT_H
|
||||
|
||||
#include "id3v2frame.h"
|
||||
#include "id3v2header.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! 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
|
||||
* labelled with a content description (which may be blank), a required
|
||||
* mime-type, and a file name (may be blank). The content description
|
||||
* uniquely identifies the GEOB frame in the tag.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT GeneralEncapsulatedObjectFrame : public Frame
|
||||
{
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
|
||||
/*!
|
||||
* Constructs an empty object frame. The description, file name and text
|
||||
* encoding should be set manually.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* Destroys the GeneralEncapsulatedObjectFrame instance.
|
||||
*/
|
||||
virtual ~GeneralEncapsulatedObjectFrame();
|
||||
|
||||
/*!
|
||||
* Returns a string containing the description, file name and mime-type
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Set the text encoding used for the description and file name.
|
||||
*
|
||||
* \see description()
|
||||
* \see fileName()
|
||||
*/
|
||||
void setTextEncoding(String::Type encoding);
|
||||
|
||||
/*!
|
||||
* Returns the mime type of the object.
|
||||
*/
|
||||
String mimeType() const;
|
||||
|
||||
/*!
|
||||
* Sets the mime type of the object.
|
||||
*/
|
||||
void setMimeType(const String &type);
|
||||
|
||||
/*!
|
||||
* Returns the file name of the object.
|
||||
*
|
||||
* \see setFileName()
|
||||
*/
|
||||
String fileName() const;
|
||||
|
||||
/*!
|
||||
* Sets the file name for the object.
|
||||
*
|
||||
* \see fileName()
|
||||
*/
|
||||
void setFileName(const String &name);
|
||||
|
||||
/*!
|
||||
* Returns the content description of the object.
|
||||
*
|
||||
* \see setDescription()
|
||||
* \see textEncoding()
|
||||
* \see setTextEncoding()
|
||||
*/
|
||||
|
||||
String description() const;
|
||||
|
||||
/*!
|
||||
* Sets the content description of the object to \a desc.
|
||||
*
|
||||
* \see description()
|
||||
* \see textEncoding()
|
||||
* \see setTextEncoding()
|
||||
*/
|
||||
|
||||
void setDescription(const String &desc);
|
||||
|
||||
/*!
|
||||
* Returns the object data as a ByteVector.
|
||||
*
|
||||
* \note ByteVector has a data() method that returns a const char * which
|
||||
* should make it easy to export this data to external programs.
|
||||
*
|
||||
* \see setObject()
|
||||
* \see mimeType()
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* \see object()
|
||||
* \see mimeType()
|
||||
* \see setMimeType()
|
||||
*/
|
||||
void setObject(const ByteVector &object);
|
||||
|
||||
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 &);
|
||||
|
||||
class GeneralEncapsulatedObjectFramePrivate;
|
||||
GeneralEncapsulatedObjectFramePrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
171
3rdparty/taglib/mpeg/id3v2/frames/ownershipframe.cpp
vendored
Normal file
171
3rdparty/taglib/mpeg/id3v2/frames/ownershipframe.cpp
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2012 by Rupert Daniel
|
||||
email : rupert@cancelmonday.com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tdebug.h>
|
||||
#include <tstringlist.h>
|
||||
#include <id3v2tag.h>
|
||||
|
||||
#include "ownershipframe.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class OwnershipFrame::OwnershipFramePrivate
|
||||
{
|
||||
public:
|
||||
String pricePaid;
|
||||
String datePurchased;
|
||||
String seller;
|
||||
String::Type textEncoding;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
OwnershipFrame::OwnershipFrame(String::Type encoding) :
|
||||
Frame("OWNE"),
|
||||
d(new OwnershipFramePrivate())
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
OwnershipFrame::OwnershipFrame(const ByteVector &data) :
|
||||
Frame(data),
|
||||
d(new OwnershipFramePrivate())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
|
||||
OwnershipFrame::~OwnershipFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String OwnershipFrame::toString() const
|
||||
{
|
||||
return "pricePaid=" + d->pricePaid + " datePurchased=" + d->datePurchased + " seller=" + d->seller;
|
||||
}
|
||||
|
||||
String OwnershipFrame::pricePaid() const
|
||||
{
|
||||
return d->pricePaid;
|
||||
}
|
||||
|
||||
void OwnershipFrame::setPricePaid(const String &s)
|
||||
{
|
||||
d->pricePaid = s;
|
||||
}
|
||||
|
||||
String OwnershipFrame::datePurchased() const
|
||||
{
|
||||
return d->datePurchased;
|
||||
}
|
||||
|
||||
void OwnershipFrame::setDatePurchased(const String &s)
|
||||
{
|
||||
d->datePurchased = s;
|
||||
}
|
||||
|
||||
String OwnershipFrame::seller() const
|
||||
{
|
||||
return d->seller;
|
||||
}
|
||||
|
||||
void OwnershipFrame::setSeller(const String &s)
|
||||
{
|
||||
d->seller = s;
|
||||
}
|
||||
|
||||
String::Type OwnershipFrame::textEncoding() const
|
||||
{
|
||||
return d->textEncoding;
|
||||
}
|
||||
|
||||
void OwnershipFrame::setTextEncoding(String::Type encoding)
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void OwnershipFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
int pos = 0;
|
||||
|
||||
// Get the text encoding
|
||||
d->textEncoding = String::Type(data[0]);
|
||||
pos += 1;
|
||||
|
||||
// Read the price paid this is a null terminate string
|
||||
d->pricePaid = readStringField(data, String::Latin1, &pos);
|
||||
|
||||
// If we don't have at least 8 bytes left then don't parse the rest of the
|
||||
// data
|
||||
if(data.size() - pos < 8) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Read the date purchased YYYYMMDD
|
||||
d->datePurchased = String(data.mid(pos, 8));
|
||||
pos += 8;
|
||||
|
||||
// Read the seller
|
||||
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
|
||||
{
|
||||
StringList sl;
|
||||
sl.append(d->seller);
|
||||
|
||||
const String::Type encoding = checkTextEncoding(sl, d->textEncoding);
|
||||
|
||||
ByteVector v;
|
||||
|
||||
v.append(char(encoding));
|
||||
v.append(d->pricePaid.data(String::Latin1));
|
||||
v.append(textDelimiter(String::Latin1));
|
||||
v.append(d->datePurchased.data(String::Latin1));
|
||||
v.append(d->seller.data(encoding));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
OwnershipFrame::OwnershipFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new OwnershipFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
151
3rdparty/taglib/mpeg/id3v2/frames/ownershipframe.h
vendored
Normal file
151
3rdparty/taglib/mpeg/id3v2/frames/ownershipframe.h
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2012 by Rupert Daniel
|
||||
email : rupert@cancelmonday.com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_OWNERSHIPFRAME_H
|
||||
#define TAGLIB_OWNERSHIPFRAME_H
|
||||
|
||||
#include "id3v2frame.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! 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;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Construct an empty ownership frame.
|
||||
*/
|
||||
explicit OwnershipFrame(String::Type encoding = String::Latin1);
|
||||
|
||||
/*!
|
||||
* Construct a ownership based on the data in \a data.
|
||||
*/
|
||||
explicit OwnershipFrame(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Destroys this OwnershipFrame instance.
|
||||
*/
|
||||
virtual ~OwnershipFrame();
|
||||
|
||||
/*!
|
||||
* Returns the text of this popularimeter.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
* Returns the date purchased.
|
||||
*
|
||||
* \see setDatePurchased()
|
||||
*/
|
||||
String datePurchased() const;
|
||||
|
||||
/*!
|
||||
* Set the date purchased.
|
||||
*
|
||||
* \see datePurchased()
|
||||
*/
|
||||
void setDatePurchased(const String &datePurchased);
|
||||
|
||||
/*!
|
||||
* Returns the price paid.
|
||||
*
|
||||
* \see setPricePaid()
|
||||
*/
|
||||
String pricePaid() const;
|
||||
|
||||
/*!
|
||||
* Set the price paid.
|
||||
*
|
||||
* \see pricePaid()
|
||||
*/
|
||||
void setPricePaid(const String &pricePaid);
|
||||
|
||||
/*!
|
||||
* Returns the seller.
|
||||
*
|
||||
* \see setSeller()
|
||||
*/
|
||||
String seller() const;
|
||||
|
||||
/*!
|
||||
* Set the seller.
|
||||
*
|
||||
* \see 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.
|
||||
*
|
||||
* \see setTextEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
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);
|
||||
|
||||
protected:
|
||||
// Reimplementations.
|
||||
|
||||
virtual void parseFields(const ByteVector &data);
|
||||
virtual ByteVector renderFields() const;
|
||||
|
||||
private:
|
||||
/*!
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
OwnershipFrame(const ByteVector &data, Header *h);
|
||||
OwnershipFrame(const OwnershipFrame &);
|
||||
OwnershipFrame &operator=(const OwnershipFrame &);
|
||||
|
||||
class OwnershipFramePrivate;
|
||||
OwnershipFramePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
81
3rdparty/taglib/mpeg/id3v2/frames/podcastframe.cpp
vendored
Normal file
81
3rdparty/taglib/mpeg/id3v2/frames/podcastframe.cpp
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2015 by Urs Fleisch
|
||||
email : ufleisch@users.sourceforge.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include "podcastframe.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class PodcastFrame::PodcastFramePrivate
|
||||
{
|
||||
public:
|
||||
ByteVector fieldData;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PodcastFrame::PodcastFrame() :
|
||||
Frame("PCST"),
|
||||
d(new PodcastFramePrivate())
|
||||
{
|
||||
d->fieldData = ByteVector(4, '\0');
|
||||
}
|
||||
|
||||
PodcastFrame::~PodcastFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String PodcastFrame::toString() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PodcastFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
d->fieldData = data;
|
||||
}
|
||||
|
||||
ByteVector PodcastFrame::renderFields() const
|
||||
{
|
||||
return d->fieldData;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PodcastFrame::PodcastFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new PodcastFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
80
3rdparty/taglib/mpeg/id3v2/frames/podcastframe.h
vendored
Normal file
80
3rdparty/taglib/mpeg/id3v2/frames/podcastframe.h
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2015 by Urs Fleisch
|
||||
email : ufleisch@users.sourceforge.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_PODCASTFRAME_H
|
||||
#define TAGLIB_PODCASTFRAME_H
|
||||
|
||||
#include "id3v2frame.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! ID3v2 podcast frame
|
||||
/*!
|
||||
* An implementation of ID3v2 podcast flag, a frame with four zero bytes.
|
||||
*/
|
||||
class TAGLIB_EXPORT PodcastFrame : public Frame
|
||||
{
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Construct a podcast frame.
|
||||
*/
|
||||
PodcastFrame();
|
||||
|
||||
/*!
|
||||
* Destroys this PodcastFrame instance.
|
||||
*/
|
||||
virtual ~PodcastFrame();
|
||||
|
||||
/*!
|
||||
* Returns a null string.
|
||||
*/
|
||||
virtual String toString() const;
|
||||
|
||||
protected:
|
||||
// Reimplementations.
|
||||
|
||||
virtual void parseFields(const ByteVector &data);
|
||||
virtual ByteVector renderFields() const;
|
||||
|
||||
private:
|
||||
/*!
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
PodcastFrame(const ByteVector &data, Header *h);
|
||||
PodcastFrame(const PodcastFrame &);
|
||||
PodcastFrame &operator=(const PodcastFrame &);
|
||||
|
||||
class PodcastFramePrivate;
|
||||
PodcastFramePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
140
3rdparty/taglib/mpeg/id3v2/frames/popularimeterframe.cpp
vendored
Normal file
140
3rdparty/taglib/mpeg/id3v2/frames/popularimeterframe.cpp
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2008 by Lukas Lalinsky
|
||||
email : lalinsky@gmail.com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tdebug.h>
|
||||
|
||||
#include "popularimeterframe.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class PopularimeterFrame::PopularimeterFramePrivate
|
||||
{
|
||||
public:
|
||||
PopularimeterFramePrivate() : rating(0), counter(0) {}
|
||||
String email;
|
||||
int rating;
|
||||
unsigned int counter;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PopularimeterFrame::PopularimeterFrame() :
|
||||
Frame("POPM"),
|
||||
d(new PopularimeterFramePrivate())
|
||||
{
|
||||
}
|
||||
|
||||
PopularimeterFrame::PopularimeterFrame(const ByteVector &data) :
|
||||
Frame(data),
|
||||
d(new PopularimeterFramePrivate())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
|
||||
PopularimeterFrame::~PopularimeterFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String PopularimeterFrame::toString() const
|
||||
{
|
||||
return d->email + " rating=" + String::number(d->rating) + " counter=" + String::number(d->counter);
|
||||
}
|
||||
|
||||
String PopularimeterFrame::email() const
|
||||
{
|
||||
return d->email;
|
||||
}
|
||||
|
||||
void PopularimeterFrame::setEmail(const String &s)
|
||||
{
|
||||
d->email = s;
|
||||
}
|
||||
|
||||
int PopularimeterFrame::rating() const
|
||||
{
|
||||
return d->rating;
|
||||
}
|
||||
|
||||
void PopularimeterFrame::setRating(int s)
|
||||
{
|
||||
d->rating = s;
|
||||
}
|
||||
|
||||
unsigned int PopularimeterFrame::counter() const
|
||||
{
|
||||
return d->counter;
|
||||
}
|
||||
|
||||
void PopularimeterFrame::setCounter(unsigned int s)
|
||||
{
|
||||
d->counter = s;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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) {
|
||||
d->rating = (unsigned char)(data[pos++]);
|
||||
if(pos < size) {
|
||||
d->counter = data.toUInt(static_cast<unsigned int>(pos));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector PopularimeterFrame::renderFields() const
|
||||
{
|
||||
ByteVector data;
|
||||
|
||||
data.append(d->email.data(String::Latin1));
|
||||
data.append(textDelimiter(String::Latin1));
|
||||
data.append(char(d->rating));
|
||||
data.append(ByteVector::fromUInt(d->counter));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PopularimeterFrame::PopularimeterFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new PopularimeterFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
132
3rdparty/taglib/mpeg/id3v2/frames/popularimeterframe.h
vendored
Normal file
132
3rdparty/taglib/mpeg/id3v2/frames/popularimeterframe.h
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2008 by Lukas Lalinsky
|
||||
email : lalinsky@gmail.com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_POPULARIMETERFRAME_H
|
||||
#define TAGLIB_POPULARIMETERFRAME_H
|
||||
|
||||
#include "id3v2frame.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! 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;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Construct an empty popularimeter frame.
|
||||
*/
|
||||
explicit PopularimeterFrame();
|
||||
|
||||
/*!
|
||||
* Construct a popularimeter based on the data in \a data.
|
||||
*/
|
||||
explicit PopularimeterFrame(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Destroys this PopularimeterFrame instance.
|
||||
*/
|
||||
virtual ~PopularimeterFrame();
|
||||
|
||||
/*!
|
||||
* Returns the text of this popularimeter.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
* Returns the email.
|
||||
*
|
||||
* \see setEmail()
|
||||
*/
|
||||
String email() const;
|
||||
|
||||
/*!
|
||||
* Set the email.
|
||||
*
|
||||
* \see email()
|
||||
*/
|
||||
void setEmail(const String &email);
|
||||
|
||||
/*!
|
||||
* Returns the rating.
|
||||
*
|
||||
* \see setRating()
|
||||
*/
|
||||
int rating() const;
|
||||
|
||||
/*!
|
||||
* Set the rating.
|
||||
*
|
||||
* \see rating()
|
||||
*/
|
||||
void setRating(int rating);
|
||||
|
||||
/*!
|
||||
* Returns the counter.
|
||||
*
|
||||
* \see setCounter()
|
||||
*/
|
||||
unsigned int counter() const;
|
||||
|
||||
/*!
|
||||
* Set the counter.
|
||||
*
|
||||
* \see counter()
|
||||
*/
|
||||
void setCounter(unsigned int counter);
|
||||
|
||||
protected:
|
||||
// Reimplementations.
|
||||
|
||||
virtual void parseFields(const ByteVector &data);
|
||||
virtual ByteVector renderFields() const;
|
||||
|
||||
private:
|
||||
/*!
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
PopularimeterFrame(const ByteVector &data, Header *h);
|
||||
PopularimeterFrame(const PopularimeterFrame &);
|
||||
PopularimeterFrame &operator=(const PopularimeterFrame &);
|
||||
|
||||
class PopularimeterFramePrivate;
|
||||
PopularimeterFramePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
131
3rdparty/taglib/mpeg/id3v2/frames/privateframe.cpp
vendored
Normal file
131
3rdparty/taglib/mpeg/id3v2/frames/privateframe.cpp
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2008 by Serkan Kalyoncu
|
||||
copyright : (C) 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tbytevectorlist.h>
|
||||
#include <id3v2tag.h>
|
||||
#include <tdebug.h>
|
||||
|
||||
#include "privateframe.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
|
||||
class PrivateFrame::PrivateFramePrivate
|
||||
{
|
||||
public:
|
||||
ByteVector data;
|
||||
String owner;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PrivateFrame::PrivateFrame() :
|
||||
Frame("PRIV"),
|
||||
d(new PrivateFramePrivate())
|
||||
{
|
||||
}
|
||||
|
||||
PrivateFrame::PrivateFrame(const ByteVector &data) :
|
||||
Frame(data),
|
||||
d(new PrivateFramePrivate())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
|
||||
PrivateFrame::~PrivateFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String PrivateFrame::toString() const
|
||||
{
|
||||
return d->owner;
|
||||
}
|
||||
|
||||
String PrivateFrame::owner() const
|
||||
{
|
||||
return d->owner;
|
||||
}
|
||||
|
||||
ByteVector PrivateFrame::data() const
|
||||
{
|
||||
return d->data;
|
||||
}
|
||||
|
||||
void PrivateFrame::setOwner(const String &s)
|
||||
{
|
||||
d->owner = s;
|
||||
}
|
||||
|
||||
void PrivateFrame::setData(const ByteVector & data)
|
||||
{
|
||||
d->data = data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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 endOfOwner = data.find(textDelimiter(String::Latin1), 0, byteAlign);
|
||||
|
||||
d->owner = String(data.mid(0, endOfOwner));
|
||||
d->data = data.mid(endOfOwner + 1);
|
||||
}
|
||||
|
||||
ByteVector PrivateFrame::renderFields() const
|
||||
{
|
||||
ByteVector v;
|
||||
|
||||
v.append(d->owner.data(String::Latin1));
|
||||
v.append(textDelimiter(String::Latin1));
|
||||
v.append(d->data);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PrivateFrame::PrivateFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new PrivateFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
111
3rdparty/taglib/mpeg/id3v2/frames/privateframe.h
vendored
Normal file
111
3rdparty/taglib/mpeg/id3v2/frames/privateframe.h
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2008 by Serkan Kalyoncu
|
||||
copyright : (C) 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_PRIVATEFRAME_H
|
||||
#define TAGLIB_PRIVATEFRAME_H
|
||||
|
||||
#include "id3v2frame.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! An implementation of ID3v2 privateframe
|
||||
|
||||
class TAGLIB_EXPORT PrivateFrame : public Frame
|
||||
{
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Construct an empty private frame.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* Destroys this private frame instance.
|
||||
*/
|
||||
virtual ~PrivateFrame();
|
||||
|
||||
/*!
|
||||
* Returns the text of this private frame, currently just the owner.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
*
|
||||
*/
|
||||
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 setData(const ByteVector &v);
|
||||
|
||||
protected:
|
||||
// Reimplementations.
|
||||
|
||||
virtual void parseFields(const ByteVector &data);
|
||||
virtual ByteVector renderFields() const;
|
||||
|
||||
private:
|
||||
/*!
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
PrivateFrame(const ByteVector &data, Header *h);
|
||||
|
||||
PrivateFrame(const PrivateFrame &);
|
||||
PrivateFrame &operator=(const PrivateFrame &);
|
||||
|
||||
class PrivateFramePrivate;
|
||||
PrivateFramePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
233
3rdparty/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp
vendored
Normal file
233
3rdparty/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp
vendored
Normal file
@@ -0,0 +1,233 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tdebug.h>
|
||||
#include <tmap.h>
|
||||
|
||||
#include "relativevolumeframe.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
struct ChannelData
|
||||
{
|
||||
ChannelData() : channelType(RelativeVolumeFrame::Other), volumeAdjustment(0) {}
|
||||
|
||||
RelativeVolumeFrame::ChannelType channelType;
|
||||
short volumeAdjustment;
|
||||
RelativeVolumeFrame::PeakVolume peakVolume;
|
||||
};
|
||||
|
||||
class RelativeVolumeFrame::RelativeVolumeFramePrivate
|
||||
{
|
||||
public:
|
||||
String identification;
|
||||
Map<ChannelType, ChannelData> channels;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RelativeVolumeFrame::RelativeVolumeFrame() :
|
||||
Frame("RVA2"),
|
||||
d(new RelativeVolumeFramePrivate())
|
||||
{
|
||||
}
|
||||
|
||||
RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data) :
|
||||
Frame(data),
|
||||
d(new RelativeVolumeFramePrivate())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
|
||||
RelativeVolumeFrame::~RelativeVolumeFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String RelativeVolumeFrame::toString() const
|
||||
{
|
||||
return d->identification;
|
||||
}
|
||||
|
||||
List<RelativeVolumeFrame::ChannelType> RelativeVolumeFrame::channels() const
|
||||
{
|
||||
List<ChannelType> l;
|
||||
|
||||
Map<ChannelType, ChannelData>::ConstIterator it = d->channels.begin();
|
||||
for(; it != d->channels.end(); ++it)
|
||||
l.append((*it).first);
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
// deprecated
|
||||
|
||||
RelativeVolumeFrame::ChannelType RelativeVolumeFrame::channelType() const
|
||||
{
|
||||
return MasterVolume;
|
||||
}
|
||||
|
||||
// deprecated
|
||||
|
||||
void RelativeVolumeFrame::setChannelType(ChannelType)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
short RelativeVolumeFrame::volumeAdjustmentIndex(ChannelType type) const
|
||||
{
|
||||
return d->channels.contains(type) ? d->channels[type].volumeAdjustment : 0;
|
||||
}
|
||||
|
||||
short RelativeVolumeFrame::volumeAdjustmentIndex() const
|
||||
{
|
||||
return volumeAdjustmentIndex(MasterVolume);
|
||||
}
|
||||
|
||||
void RelativeVolumeFrame::setVolumeAdjustmentIndex(short index, ChannelType type)
|
||||
{
|
||||
d->channels[type].volumeAdjustment = index;
|
||||
}
|
||||
|
||||
void RelativeVolumeFrame::setVolumeAdjustmentIndex(short index)
|
||||
{
|
||||
setVolumeAdjustmentIndex(index, MasterVolume);
|
||||
}
|
||||
|
||||
float RelativeVolumeFrame::volumeAdjustment(ChannelType type) const
|
||||
{
|
||||
return d->channels.contains(type) ? float(d->channels[type].volumeAdjustment) / float(512) : 0;
|
||||
}
|
||||
|
||||
float RelativeVolumeFrame::volumeAdjustment() const
|
||||
{
|
||||
return volumeAdjustment(MasterVolume);
|
||||
}
|
||||
|
||||
void RelativeVolumeFrame::setVolumeAdjustment(float adjustment, ChannelType type)
|
||||
{
|
||||
d->channels[type].volumeAdjustment = short(adjustment * float(512));
|
||||
}
|
||||
|
||||
void RelativeVolumeFrame::setVolumeAdjustment(float adjustment)
|
||||
{
|
||||
setVolumeAdjustment(adjustment, MasterVolume);
|
||||
}
|
||||
|
||||
RelativeVolumeFrame::PeakVolume RelativeVolumeFrame::peakVolume(ChannelType type) const
|
||||
{
|
||||
return d->channels.contains(type) ? d->channels[type].peakVolume : PeakVolume();
|
||||
}
|
||||
|
||||
RelativeVolumeFrame::PeakVolume RelativeVolumeFrame::peakVolume() const
|
||||
{
|
||||
return peakVolume(MasterVolume);
|
||||
}
|
||||
|
||||
void RelativeVolumeFrame::setPeakVolume(const PeakVolume &peak, ChannelType type)
|
||||
{
|
||||
d->channels[type].peakVolume = peak;
|
||||
}
|
||||
|
||||
void RelativeVolumeFrame::setPeakVolume(const PeakVolume &peak)
|
||||
{
|
||||
setPeakVolume(peak, MasterVolume);
|
||||
}
|
||||
|
||||
String RelativeVolumeFrame::identification() const
|
||||
{
|
||||
return d->identification;
|
||||
}
|
||||
|
||||
void RelativeVolumeFrame::setIdentification(const String &s)
|
||||
{
|
||||
d->identification = s;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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) {
|
||||
|
||||
ChannelType type = ChannelType(data[pos]);
|
||||
pos += 1;
|
||||
|
||||
ChannelData &channel = d->channels[type];
|
||||
|
||||
channel.volumeAdjustment = data.toShort(static_cast<unsigned int>(pos));
|
||||
pos += 2;
|
||||
|
||||
channel.peakVolume.bitsRepresentingPeak = data[pos];
|
||||
pos += 1;
|
||||
|
||||
const int bytes = (channel.peakVolume.bitsRepresentingPeak + 7) / 8;
|
||||
channel.peakVolume.peakVolume = data.mid(pos, bytes);
|
||||
pos += bytes;
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector RelativeVolumeFrame::renderFields() const
|
||||
{
|
||||
ByteVector data;
|
||||
|
||||
data.append(d->identification.data(String::Latin1));
|
||||
data.append(textDelimiter(String::Latin1));
|
||||
|
||||
Map<ChannelType, ChannelData>::ConstIterator it = d->channels.begin();
|
||||
|
||||
for(; it != d->channels.end(); ++it) {
|
||||
ChannelType type = (*it).first;
|
||||
const ChannelData &channel = (*it).second;
|
||||
|
||||
data.append(char(type));
|
||||
data.append(ByteVector::fromShort(channel.volumeAdjustment));
|
||||
data.append(char(channel.peakVolume.bitsRepresentingPeak));
|
||||
data.append(channel.peakVolume.peakVolume);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new RelativeVolumeFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
274
3rdparty/taglib/mpeg/id3v2/frames/relativevolumeframe.h
vendored
Normal file
274
3rdparty/taglib/mpeg/id3v2/frames/relativevolumeframe.h
vendored
Normal file
@@ -0,0 +1,274 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_RELATIVEVOLUMEFRAME_H
|
||||
#define TAGLIB_RELATIVEVOLUMEFRAME_H
|
||||
|
||||
#include "tlist.h"
|
||||
#include "id3v2frame.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! 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.
|
||||
*
|
||||
* Multiple relative volume adjustment frames may be present in the tag
|
||||
* each with a unique identification and describing volume adjustment for
|
||||
* different channel types.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT RelativeVolumeFrame : public Frame
|
||||
{
|
||||
friend class FrameFactory;
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
//! 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
|
||||
{
|
||||
/*!
|
||||
* Constructs an empty peak volume description.
|
||||
*/
|
||||
PeakVolume() : bitsRepresentingPeak(0) {}
|
||||
/*!
|
||||
* The number of bits (in the range of 0 to 255) used to describe the
|
||||
* peak volume.
|
||||
*/
|
||||
unsigned char bitsRepresentingPeak;
|
||||
/*!
|
||||
* The array of bits (represented as a series of bytes) used to describe
|
||||
* the peak volume.
|
||||
*/
|
||||
ByteVector peakVolume;
|
||||
};
|
||||
|
||||
/*!
|
||||
* Constructs a RelativeVolumeFrame. The relevant data should be set
|
||||
* manually.
|
||||
*/
|
||||
RelativeVolumeFrame();
|
||||
|
||||
/*!
|
||||
* Constructs a RelativeVolumeFrame based on the contents of \a data.
|
||||
*/
|
||||
RelativeVolumeFrame(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Destroys the RelativeVolumeFrame instance.
|
||||
*/
|
||||
virtual ~RelativeVolumeFrame();
|
||||
|
||||
/*!
|
||||
* Returns the frame's identification.
|
||||
*
|
||||
* \see identification()
|
||||
*/
|
||||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
* Returns a list of channels with information currently in the frame.
|
||||
*/
|
||||
List<ChannelType> channels() const;
|
||||
|
||||
/*!
|
||||
* \deprecated Always returns master volume.
|
||||
*/
|
||||
ChannelType channelType() const;
|
||||
|
||||
/*!
|
||||
* \deprecated This method no longer has any effect.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
|
||||
#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.
|
||||
*
|
||||
* This defaults to returning the value for the master volume channel if
|
||||
* available and returns 0 if the specified channel does not exist.
|
||||
*
|
||||
* \see setVolumeAdjustmentIndex()
|
||||
* \see volumeAjustment()
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* By default this sets the value for the master volume.
|
||||
*
|
||||
* \see volumeAdjustmentIndex()
|
||||
* \see setVolumeAjustment()
|
||||
*/
|
||||
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
|
||||
* value the value returned by this method may not be identical to the
|
||||
* value set using setVolumeAdjustment().
|
||||
*
|
||||
* This defaults to returning the value for the master volume channel if
|
||||
* available and returns 0 if the specified channel does not exist.
|
||||
*
|
||||
* \see setVolumeAdjustment()
|
||||
* \see volumeAdjustmentIndex()
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* \note Because this is actually stored internally as an "index" to this
|
||||
* value the value set by this method may not be identical to the one
|
||||
* returned by volumeAdjustment().
|
||||
*
|
||||
* \see setVolumeAdjustment()
|
||||
* \see volumeAdjustmentIndex()
|
||||
*/
|
||||
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
|
||||
* available and returns 0 if the specified channel does not exist.
|
||||
*
|
||||
* \see setPeakVolume()
|
||||
*/
|
||||
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);
|
||||
|
||||
#else
|
||||
|
||||
// BIC: Combine each of the following pairs of functions (or maybe just
|
||||
// rework this junk altogether).
|
||||
|
||||
short volumeAdjustmentIndex(ChannelType type) const;
|
||||
short volumeAdjustmentIndex() const;
|
||||
|
||||
void setVolumeAdjustmentIndex(short index, ChannelType type);
|
||||
void setVolumeAdjustmentIndex(short index);
|
||||
|
||||
float volumeAdjustment(ChannelType type) const;
|
||||
float volumeAdjustment() const;
|
||||
|
||||
void setVolumeAdjustment(float adjustment, ChannelType type);
|
||||
void setVolumeAdjustment(float adjustment);
|
||||
|
||||
PeakVolume peakVolume(ChannelType type) const;
|
||||
PeakVolume peakVolume() const;
|
||||
|
||||
void setPeakVolume(const PeakVolume &peak, ChannelType type);
|
||||
void setPeakVolume(const PeakVolume &peak);
|
||||
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* Returns the identification for this frame.
|
||||
*/
|
||||
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);
|
||||
|
||||
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 &);
|
||||
|
||||
class RelativeVolumeFramePrivate;
|
||||
RelativeVolumeFramePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
242
3rdparty/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.cpp
vendored
Normal file
242
3rdparty/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.cpp
vendored
Normal file
@@ -0,0 +1,242 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2014 by Urs Fleisch
|
||||
email : ufleisch@users.sourceforge.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include "synchronizedlyricsframe.h"
|
||||
#include <tbytevectorlist.h>
|
||||
#include <id3v2tag.h>
|
||||
#include <tdebug.h>
|
||||
#include <tpropertymap.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class SynchronizedLyricsFrame::SynchronizedLyricsFramePrivate
|
||||
{
|
||||
public:
|
||||
SynchronizedLyricsFramePrivate() :
|
||||
textEncoding(String::Latin1),
|
||||
timestampFormat(SynchronizedLyricsFrame::AbsoluteMilliseconds),
|
||||
type(SynchronizedLyricsFrame::Lyrics) {}
|
||||
String::Type textEncoding;
|
||||
ByteVector language;
|
||||
SynchronizedLyricsFrame::TimestampFormat timestampFormat;
|
||||
SynchronizedLyricsFrame::Type type;
|
||||
String description;
|
||||
SynchronizedLyricsFrame::SynchedTextList synchedText;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SynchronizedLyricsFrame::SynchronizedLyricsFrame(String::Type encoding) :
|
||||
Frame("SYLT"),
|
||||
d(new SynchronizedLyricsFramePrivate())
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
SynchronizedLyricsFrame::SynchronizedLyricsFrame(const ByteVector &data) :
|
||||
Frame(data),
|
||||
d(new SynchronizedLyricsFramePrivate())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
|
||||
SynchronizedLyricsFrame::~SynchronizedLyricsFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String SynchronizedLyricsFrame::toString() const
|
||||
{
|
||||
return d->description;
|
||||
}
|
||||
|
||||
String::Type SynchronizedLyricsFrame::textEncoding() const
|
||||
{
|
||||
return d->textEncoding;
|
||||
}
|
||||
|
||||
ByteVector SynchronizedLyricsFrame::language() const
|
||||
{
|
||||
return d->language;
|
||||
}
|
||||
|
||||
SynchronizedLyricsFrame::TimestampFormat
|
||||
SynchronizedLyricsFrame::timestampFormat() const
|
||||
{
|
||||
return d->timestampFormat;
|
||||
}
|
||||
|
||||
SynchronizedLyricsFrame::Type SynchronizedLyricsFrame::type() const
|
||||
{
|
||||
return d->type;
|
||||
}
|
||||
|
||||
String SynchronizedLyricsFrame::description() const
|
||||
{
|
||||
return d->description;
|
||||
}
|
||||
|
||||
SynchronizedLyricsFrame::SynchedTextList
|
||||
SynchronizedLyricsFrame::synchedText() const
|
||||
{
|
||||
return d->synchedText;
|
||||
}
|
||||
|
||||
void SynchronizedLyricsFrame::setTextEncoding(String::Type encoding)
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
void SynchronizedLyricsFrame::setLanguage(const ByteVector &languageEncoding)
|
||||
{
|
||||
d->language = languageEncoding.mid(0, 3);
|
||||
}
|
||||
|
||||
void SynchronizedLyricsFrame::setTimestampFormat(SynchronizedLyricsFrame::TimestampFormat f)
|
||||
{
|
||||
d->timestampFormat = f;
|
||||
}
|
||||
|
||||
void SynchronizedLyricsFrame::setType(SynchronizedLyricsFrame::Type t)
|
||||
{
|
||||
d->type = t;
|
||||
}
|
||||
|
||||
void SynchronizedLyricsFrame::setDescription(const String &s)
|
||||
{
|
||||
d->description = s;
|
||||
}
|
||||
|
||||
void SynchronizedLyricsFrame::setSynchedText(
|
||||
const SynchronizedLyricsFrame::SynchedTextList &t)
|
||||
{
|
||||
d->synchedText = t;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SynchronizedLyricsFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
const int end = data.size();
|
||||
if(end < 7) {
|
||||
debug("A synchronized lyrics frame must contain at least 7 bytes.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->textEncoding = String::Type(data[0]);
|
||||
d->language = data.mid(1, 3);
|
||||
d->timestampFormat = TimestampFormat(data[4]);
|
||||
d->type = Type(data[5]);
|
||||
|
||||
int pos = 6;
|
||||
|
||||
d->description = readStringField(data, d->textEncoding, &pos);
|
||||
if(pos == 6)
|
||||
return;
|
||||
|
||||
/*
|
||||
* If UTF16 strings are found in SYLT frames, a BOM may only be
|
||||
* present in the first string (content descriptor), and the strings of
|
||||
* the synchronized text have no BOM. Here the BOM is read from
|
||||
* the first string to have a specific encoding with endianness for the
|
||||
* case of strings without BOM so that readStringField() will work.
|
||||
*/
|
||||
String::Type encWithEndianness = d->textEncoding;
|
||||
if(d->textEncoding == String::UTF16) {
|
||||
unsigned short bom = data.toUShort(6, true);
|
||||
if(bom == 0xfffe) {
|
||||
encWithEndianness = String::UTF16LE;
|
||||
} else if(bom == 0xfeff) {
|
||||
encWithEndianness = String::UTF16BE;
|
||||
}
|
||||
}
|
||||
|
||||
d->synchedText.clear();
|
||||
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) {
|
||||
unsigned short bom = data.toUShort(pos, true);
|
||||
if(bom != 0xfffe && bom != 0xfeff) {
|
||||
enc = encWithEndianness;
|
||||
}
|
||||
}
|
||||
String text = readStringField(data, enc, &pos);
|
||||
if(pos + 4 > end)
|
||||
return;
|
||||
|
||||
unsigned int time = data.toUInt(pos, true);
|
||||
pos += 4;
|
||||
|
||||
d->synchedText.append(SynchedText(time, text));
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
encoding = checkTextEncoding(it->text, encoding);
|
||||
}
|
||||
|
||||
v.append(char(encoding));
|
||||
v.append(d->language.size() == 3 ? d->language : "XXX");
|
||||
v.append(char(d->timestampFormat));
|
||||
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) {
|
||||
const SynchedText &entry = *it;
|
||||
v.append(entry.text.data(encoding));
|
||||
v.append(textDelimiter(encoding));
|
||||
v.append(ByteVector::fromUInt(entry.time));
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SynchronizedLyricsFrame::SynchronizedLyricsFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new SynchronizedLyricsFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
231
3rdparty/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.h
vendored
Normal file
231
3rdparty/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.h
vendored
Normal file
@@ -0,0 +1,231 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2014 by Urs Fleisch
|
||||
email : ufleisch@users.sourceforge.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_SYNCHRONIZEDLYRICSFRAME_H
|
||||
#define TAGLIB_SYNCHRONIZEDLYRICSFRAME_H
|
||||
|
||||
#include "id3v2frame.h"
|
||||
#include "tlist.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! ID3v2 synchronized lyrics frame
|
||||
/*!
|
||||
* An implementation of ID3v2 synchronized lyrics.
|
||||
*/
|
||||
class TAGLIB_EXPORT SynchronizedLyricsFrame : public Frame
|
||||
{
|
||||
friend class FrameFactory;
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
/*!
|
||||
* 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
|
||||
};
|
||||
|
||||
/*!
|
||||
* 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;
|
||||
};
|
||||
|
||||
/*!
|
||||
* List of synchronized lyrics.
|
||||
*/
|
||||
typedef 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);
|
||||
|
||||
/*!
|
||||
* Construct a synchronized lyrics frame based on the data in \a data.
|
||||
*/
|
||||
explicit SynchronizedLyricsFrame(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Destroys this SynchronizedLyricsFrame instance.
|
||||
*/
|
||||
virtual ~SynchronizedLyricsFrame();
|
||||
|
||||
/*!
|
||||
* Returns the description of this synchronized lyrics frame.
|
||||
*
|
||||
* \see description()
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* \see setTextEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
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>.
|
||||
*
|
||||
* \note Most taggers simply ignore this value.
|
||||
*
|
||||
* \see setLanguage()
|
||||
*/
|
||||
ByteVector language() const;
|
||||
|
||||
/*!
|
||||
* Returns the timestamp format.
|
||||
*/
|
||||
TimestampFormat timestampFormat() const;
|
||||
|
||||
/*!
|
||||
* Returns the type of text contained.
|
||||
*/
|
||||
Type type() const;
|
||||
|
||||
/*!
|
||||
* Returns the description of this synchronized lyrics frame.
|
||||
*
|
||||
* \note Most taggers simply ignore this value.
|
||||
*
|
||||
* \see setDescription()
|
||||
*/
|
||||
String description() const;
|
||||
|
||||
/*!
|
||||
* Returns the text with the time stamps.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* Set the timestamp format.
|
||||
*
|
||||
* \see timestampFormat()
|
||||
*/
|
||||
void setTimestampFormat(TimestampFormat f);
|
||||
|
||||
/*!
|
||||
* Set the type of text contained.
|
||||
*
|
||||
* \see type()
|
||||
*/
|
||||
void setType(Type t);
|
||||
|
||||
/*!
|
||||
* Sets the description of the synchronized lyrics frame to \a s.
|
||||
*
|
||||
* \see description()
|
||||
*/
|
||||
void setDescription(const String &s);
|
||||
|
||||
/*!
|
||||
* Sets the text with the time stamps.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
void setSynchedText(const SynchedTextList &t);
|
||||
|
||||
protected:
|
||||
// Reimplementations.
|
||||
|
||||
virtual void parseFields(const ByteVector &data);
|
||||
virtual ByteVector renderFields() const;
|
||||
|
||||
private:
|
||||
/*!
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
SynchronizedLyricsFrame(const ByteVector &data, Header *h);
|
||||
SynchronizedLyricsFrame(const SynchronizedLyricsFrame &);
|
||||
SynchronizedLyricsFrame &operator=(const SynchronizedLyricsFrame &);
|
||||
|
||||
class SynchronizedLyricsFramePrivate;
|
||||
SynchronizedLyricsFramePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
340
3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp
vendored
Normal file
340
3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp
vendored
Normal file
@@ -0,0 +1,340 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2013 by Lukas Krejci
|
||||
email : krejclu6@fel.cvut.cz
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tbytevectorlist.h>
|
||||
#include <tpropertymap.h>
|
||||
#include <tdebug.h>
|
||||
|
||||
#include "tableofcontentsframe.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class TableOfContentsFrame::TableOfContentsFramePrivate
|
||||
{
|
||||
public:
|
||||
TableOfContentsFramePrivate() :
|
||||
tagHeader(0),
|
||||
isTopLevel(false),
|
||||
isOrdered(false)
|
||||
{
|
||||
embeddedFrameList.setAutoDelete(true);
|
||||
}
|
||||
|
||||
const ID3v2::Header *tagHeader;
|
||||
ByteVector elementID;
|
||||
bool isTopLevel;
|
||||
bool isOrdered;
|
||||
ByteVectorList childElements;
|
||||
FrameListMap embeddedFrameListMap;
|
||||
FrameList embeddedFrameList;
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
// These functions are needed to try to aim for backward compatibility with
|
||||
// an API that previously (unreasonably) required null bytes to be appeneded
|
||||
// at the end of identifiers explicitly by the API user.
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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())
|
||||
{
|
||||
d->elementID = elementID;
|
||||
strip(d->elementID);
|
||||
d->childElements = children;
|
||||
|
||||
for(FrameList::ConstIterator it = embeddedFrames.begin(); it != embeddedFrames.end(); ++it)
|
||||
addEmbeddedFrame(*it);
|
||||
}
|
||||
|
||||
TableOfContentsFrame::~TableOfContentsFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
ByteVector TableOfContentsFrame::elementID() const
|
||||
{
|
||||
return d->elementID;
|
||||
}
|
||||
|
||||
bool TableOfContentsFrame::isTopLevel() const
|
||||
{
|
||||
return d->isTopLevel;
|
||||
}
|
||||
|
||||
bool TableOfContentsFrame::isOrdered() const
|
||||
{
|
||||
return d->isOrdered;
|
||||
}
|
||||
|
||||
unsigned int TableOfContentsFrame::entryCount() const
|
||||
{
|
||||
return d->childElements.size();
|
||||
}
|
||||
|
||||
ByteVectorList TableOfContentsFrame::childElements() const
|
||||
{
|
||||
return d->childElements;
|
||||
}
|
||||
|
||||
void TableOfContentsFrame::setElementID(const ByteVector &eID)
|
||||
{
|
||||
d->elementID = eID;
|
||||
strip(d->elementID);
|
||||
}
|
||||
|
||||
void TableOfContentsFrame::setIsTopLevel(const bool &t)
|
||||
{
|
||||
d->isTopLevel = t;
|
||||
}
|
||||
|
||||
void TableOfContentsFrame::setIsOrdered(const bool &o)
|
||||
{
|
||||
d->isOrdered = o;
|
||||
}
|
||||
|
||||
void TableOfContentsFrame::setChildElements(const ByteVectorList &l)
|
||||
{
|
||||
d->childElements = l;
|
||||
strip(d->childElements);
|
||||
}
|
||||
|
||||
void TableOfContentsFrame::addChildElement(const ByteVector &cE)
|
||||
{
|
||||
d->childElements.append(cE);
|
||||
strip(d->childElements);
|
||||
}
|
||||
|
||||
void TableOfContentsFrame::removeChildElement(const ByteVector &cE)
|
||||
{
|
||||
ByteVectorList::Iterator it = d->childElements.find(cE);
|
||||
|
||||
if(it == d->childElements.end())
|
||||
it = d->childElements.find(cE + ByteVector("\0"));
|
||||
|
||||
d->childElements.erase(it);
|
||||
}
|
||||
|
||||
const FrameListMap &TableOfContentsFrame::embeddedFrameListMap() const
|
||||
{
|
||||
return d->embeddedFrameListMap;
|
||||
}
|
||||
|
||||
const FrameList &TableOfContentsFrame::embeddedFrameList() const
|
||||
{
|
||||
return d->embeddedFrameList;
|
||||
}
|
||||
|
||||
const FrameList &TableOfContentsFrame::embeddedFrameList(const ByteVector &frameID) const
|
||||
{
|
||||
return d->embeddedFrameListMap[frameID];
|
||||
}
|
||||
|
||||
void TableOfContentsFrame::addEmbeddedFrame(Frame *frame)
|
||||
{
|
||||
d->embeddedFrameList.append(frame);
|
||||
d->embeddedFrameListMap[frame->frameID()].append(frame);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// ...and from the frame list map
|
||||
it = d->embeddedFrameListMap[frame->frameID()].find(frame);
|
||||
d->embeddedFrameListMap[frame->frameID()].erase(it);
|
||||
|
||||
// ...and delete as desired
|
||||
if(del)
|
||||
delete frame;
|
||||
}
|
||||
|
||||
void TableOfContentsFrame::removeEmbeddedFrames(const ByteVector &id)
|
||||
{
|
||||
FrameList l = d->embeddedFrameListMap[id];
|
||||
for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
|
||||
removeEmbeddedFrame(*it, true);
|
||||
}
|
||||
|
||||
String TableOfContentsFrame::toString() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
PropertyMap TableOfContentsFrame::asProperties() const
|
||||
{
|
||||
PropertyMap map;
|
||||
|
||||
map.unsupportedData().append(frameID() + String("/") + d->elementID);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
TableOfContentsFrame *TableOfContentsFrame::findByElementID(const ID3v2::Tag *tag,
|
||||
const ByteVector &eID) // static
|
||||
{
|
||||
ID3v2::FrameList tablesOfContents = tag->frameList("CTOC");
|
||||
|
||||
for(ID3v2::FrameList::ConstIterator it = tablesOfContents.begin();
|
||||
it != tablesOfContents.end();
|
||||
++it)
|
||||
{
|
||||
TableOfContentsFrame *frame = dynamic_cast<TableOfContentsFrame *>(*it);
|
||||
if(frame && frame->elementID() == eID)
|
||||
return frame;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
TableOfContentsFrame *frame = dynamic_cast<TableOfContentsFrame *>(*it);
|
||||
if(frame && frame->isTopLevel() == true)
|
||||
return frame;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TableOfContentsFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
unsigned int size = data.size();
|
||||
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.");
|
||||
return;
|
||||
}
|
||||
|
||||
int pos = 0;
|
||||
unsigned int embPos = 0;
|
||||
d->elementID = readStringField(data, String::Latin1, &pos).data(String::Latin1);
|
||||
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++) {
|
||||
ByteVector childElementID = readStringField(data, String::Latin1, &pos).data(String::Latin1);
|
||||
d->childElements.append(childElementID);
|
||||
}
|
||||
|
||||
size -= pos;
|
||||
|
||||
if(size < header()->size())
|
||||
return;
|
||||
|
||||
while(embPos < size - header()->size()) {
|
||||
Frame *frame = FrameFactory::instance()->createFrame(data.mid(pos + embPos), (d->tagHeader != 0));
|
||||
|
||||
if(!frame)
|
||||
return;
|
||||
|
||||
// Checks to make sure that frame parsed correctly.
|
||||
if(frame->size() <= 0) {
|
||||
delete frame;
|
||||
return;
|
||||
}
|
||||
|
||||
embPos += frame->size() + header()->size();
|
||||
addEmbeddedFrame(frame);
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector TableOfContentsFrame::renderFields() const
|
||||
{
|
||||
ByteVector data;
|
||||
|
||||
data.append(d->elementID);
|
||||
data.append('\0');
|
||||
char flags = 0;
|
||||
if(d->isTopLevel)
|
||||
flags += 2;
|
||||
if(d->isOrdered)
|
||||
flags += 1;
|
||||
data.append(flags);
|
||||
data.append((char)(entryCount()));
|
||||
ByteVectorList::ConstIterator it = d->childElements.begin();
|
||||
while(it != d->childElements.end()) {
|
||||
data.append(*it);
|
||||
data.append('\0');
|
||||
it++;
|
||||
}
|
||||
FrameList l = d->embeddedFrameList;
|
||||
for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
|
||||
data.append((*it)->render());
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
TableOfContentsFrame::TableOfContentsFrame(const ID3v2::Header *tagHeader,
|
||||
const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new TableOfContentsFramePrivate())
|
||||
{
|
||||
d->tagHeader = tagHeader;
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
260
3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.h
vendored
Normal file
260
3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.h
vendored
Normal file
@@ -0,0 +1,260 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2013 by Lukas Krejci
|
||||
email : krejclu6@fel.cvut.cz
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_TABLEOFCONTENTSFRAME
|
||||
#define TAGLIB_TABLEOFCONTENTSFRAME
|
||||
|
||||
#include "id3v2tag.h"
|
||||
#include "id3v2frame.h"
|
||||
|
||||
#include "tbytevectorlist.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
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
|
||||
|
||||
class TAGLIB_EXPORT TableOfContentsFrame : public ID3v2::Frame
|
||||
{
|
||||
friend class FrameFactory;
|
||||
|
||||
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);
|
||||
|
||||
/*!
|
||||
* 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());
|
||||
|
||||
/*!
|
||||
* Destroys the frame.
|
||||
*/
|
||||
~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;
|
||||
|
||||
/*!
|
||||
* Returns true, if the frame is top-level (doesn't have
|
||||
* any parent CTOC frame).
|
||||
*
|
||||
* \see setIsTopLevel()
|
||||
*/
|
||||
bool isTopLevel() const;
|
||||
|
||||
/*!
|
||||
* Returns true, if the child elements list entries
|
||||
* are ordered.
|
||||
*
|
||||
* \see setIsOrdered()
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Returns list of child elements of the frame.
|
||||
*
|
||||
* \see setChildElements()
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* Sets, if the frame is top-level (doesn't have
|
||||
* any parent CTOC frame).
|
||||
*
|
||||
* \see isTopLevel()
|
||||
*/
|
||||
void setIsTopLevel(const bool &t);
|
||||
|
||||
/*!
|
||||
* Sets, if the child elements list entries
|
||||
* are ordered.
|
||||
*
|
||||
* \see isOrdered()
|
||||
*/
|
||||
void setIsOrdered(const bool &o);
|
||||
|
||||
/*!
|
||||
* Sets list of child elements of the frame to \a l.
|
||||
*
|
||||
* \see childElements()
|
||||
*/
|
||||
void setChildElements(const ByteVectorList &l);
|
||||
|
||||
/*!
|
||||
* Adds \a cE to list of child elements of the frame.
|
||||
*
|
||||
* \see childElements()
|
||||
*/
|
||||
void addChildElement(const ByteVector &cE);
|
||||
|
||||
/*!
|
||||
* Removes \a cE to list of child elements of the frame.
|
||||
*
|
||||
* \see childElements()
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* This is the most convenient structure for accessing the CTOC frame's
|
||||
* embedded frames. Many frame types allow multiple instances of the same
|
||||
* frame type so this is a map of lists. In most cases however there will
|
||||
* only be a single frame of a certain type.
|
||||
*
|
||||
* \warning You should not modify this data structure directly, instead
|
||||
* use addEmbeddedFrame() and removeEmbeddedFrame().
|
||||
*
|
||||
* \see embeddedFrameList()
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* This can be useful if for example you want iterate over the CTOC frame's
|
||||
* embedded frames in the order that they occur in the CTOC frame.
|
||||
*
|
||||
* \warning You should not modify this data structure directly, instead
|
||||
* use addEmbeddedFrame() and removeEmbeddedFrame().
|
||||
*/
|
||||
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:
|
||||
*
|
||||
* \code
|
||||
* embeddedFrameListMap()[frameID];
|
||||
* \endcode
|
||||
*
|
||||
* \see embeddedFrameListMap()
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
virtual String toString() 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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
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 &);
|
||||
|
||||
class TableOfContentsFramePrivate;
|
||||
TableOfContentsFramePrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
428
3rdparty/taglib/mpeg/id3v2/frames/textidentificationframe.cpp
vendored
Normal file
428
3rdparty/taglib/mpeg/id3v2/frames/textidentificationframe.cpp
vendored
Normal file
@@ -0,0 +1,428 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tbytevectorlist.h>
|
||||
#include <id3v2tag.h>
|
||||
#include "textidentificationframe.h"
|
||||
#include "tpropertymap.h"
|
||||
#include "id3v1genres.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class TextIdentificationFrame::TextIdentificationFramePrivate
|
||||
{
|
||||
public:
|
||||
TextIdentificationFramePrivate() : textEncoding(String::Latin1) {}
|
||||
String::Type textEncoding;
|
||||
StringList fieldList;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// TextIdentificationFrame public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
|
||||
TextIdentificationFrame *TextIdentificationFrame::createTIPLFrame(const PropertyMap &properties) // static
|
||||
{
|
||||
TextIdentificationFrame *frame = new TextIdentificationFrame("TIPL");
|
||||
StringList l;
|
||||
for(PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it){
|
||||
l.append(it->first);
|
||||
l.append(it->second.toString(",")); // comma-separated list of names
|
||||
}
|
||||
frame->setText(l);
|
||||
return frame;
|
||||
}
|
||||
|
||||
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
|
||||
continue;
|
||||
l.append(it->first.substr(instrumentPrefix.size()));
|
||||
l.append(it->second.toString(","));
|
||||
}
|
||||
frame->setText(l);
|
||||
return frame;
|
||||
}
|
||||
|
||||
TextIdentificationFrame::~TextIdentificationFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void TextIdentificationFrame::setText(const StringList &l)
|
||||
{
|
||||
d->fieldList = l;
|
||||
}
|
||||
|
||||
void TextIdentificationFrame::setText(const String &s)
|
||||
{
|
||||
d->fieldList = s;
|
||||
}
|
||||
|
||||
String TextIdentificationFrame::toString() const
|
||||
{
|
||||
return d->fieldList.toString();
|
||||
}
|
||||
|
||||
StringList TextIdentificationFrame::fieldList() const
|
||||
{
|
||||
return d->fieldList;
|
||||
}
|
||||
|
||||
String::Type TextIdentificationFrame::textEncoding() const
|
||||
{
|
||||
return d->textEncoding;
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
const KeyConversionMap &TextIdentificationFrame::involvedPeopleMap() // static
|
||||
{
|
||||
static KeyConversionMap m;
|
||||
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")
|
||||
return makeTIPLProperties();
|
||||
if(frameID() == "TMCL")
|
||||
return makeTMCLProperties();
|
||||
PropertyMap map;
|
||||
String tagName = frameIDToKey(frameID());
|
||||
if(tagName.isEmpty()) {
|
||||
map.unsupportedData().append(frameID());
|
||||
return map;
|
||||
}
|
||||
StringList values = fieldList();
|
||||
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) {
|
||||
bool ok = false;
|
||||
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) {
|
||||
// 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)
|
||||
(*it)[tpos] = ' ';
|
||||
}
|
||||
}
|
||||
PropertyMap ret;
|
||||
ret.insert(tagName, values);
|
||||
return ret;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// TextIdentificationFrame protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TextIdentificationFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
// Don't try to parse invalid frames
|
||||
|
||||
if(data.size() < 2)
|
||||
return;
|
||||
|
||||
// read the string data type (the first byte of the field data)
|
||||
|
||||
d->textEncoding = String::Type(data[0]);
|
||||
|
||||
// split the byte array into chunks based on the string type (two byte delimiter
|
||||
// for unicode encodings)
|
||||
|
||||
int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
|
||||
|
||||
// build a small counter to strip nulls off the end of the field
|
||||
|
||||
int dataLength = data.size() - 1;
|
||||
|
||||
while(dataLength > 0 && data[dataLength] == 0)
|
||||
dataLength--;
|
||||
|
||||
while(dataLength % byteAlign != 0)
|
||||
dataLength++;
|
||||
|
||||
ByteVectorList l = ByteVectorList::split(data.mid(1, dataLength), textDelimiter(d->textEncoding), byteAlign);
|
||||
|
||||
d->fieldList.clear();
|
||||
|
||||
// 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)
|
||||
d->fieldList.append(Tag::latin1StringHandler()->parse(*it));
|
||||
else
|
||||
d->fieldList.append(String(*it, d->textEncoding));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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++) {
|
||||
|
||||
// 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())
|
||||
v.append(textDelimiter(encoding));
|
||||
|
||||
v.append((*it).data(encoding));
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// TextIdentificationFrame private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new TextIdentificationFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
|
||||
PropertyMap TextIdentificationFrame::makeTIPLProperties() const
|
||||
{
|
||||
PropertyMap map;
|
||||
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) {
|
||||
bool found = false;
|
||||
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){
|
||||
// invalid involved role -> mark whole frame as unsupported in order to be consisten with writing
|
||||
map.clear();
|
||||
map.unsupportedData().append(frameID());
|
||||
return map;
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
PropertyMap TextIdentificationFrame::makeTMCLProperties() const
|
||||
{
|
||||
PropertyMap map;
|
||||
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) {
|
||||
String instrument = it->upper();
|
||||
if(instrument.isEmpty()) {
|
||||
// instrument is not a valid key -> frame unsupported
|
||||
map.clear();
|
||||
map.unsupportedData().append(frameID());
|
||||
return map;
|
||||
}
|
||||
map.insert(L"PERFORMER:" + instrument, (++it)->split(","));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// UserTextIdentificationFrame public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
UserTextIdentificationFrame::UserTextIdentificationFrame(String::Type encoding) :
|
||||
TextIdentificationFrame("TXXX", encoding),
|
||||
d(0)
|
||||
{
|
||||
StringList l;
|
||||
l.append(String());
|
||||
l.append(String());
|
||||
setText(l);
|
||||
}
|
||||
|
||||
|
||||
UserTextIdentificationFrame::UserTextIdentificationFrame(const ByteVector &data) :
|
||||
TextIdentificationFrame(data)
|
||||
{
|
||||
checkFields();
|
||||
}
|
||||
|
||||
UserTextIdentificationFrame::UserTextIdentificationFrame(const String &description, const StringList &values, String::Type encoding) :
|
||||
TextIdentificationFrame("TXXX", encoding),
|
||||
d(0)
|
||||
{
|
||||
setDescription(description);
|
||||
setText(values);
|
||||
}
|
||||
|
||||
String UserTextIdentificationFrame::toString() const
|
||||
{
|
||||
return "[" + description() + "] " + fieldList().toString();
|
||||
}
|
||||
|
||||
String UserTextIdentificationFrame::description() const
|
||||
{
|
||||
return !TextIdentificationFrame::fieldList().isEmpty()
|
||||
? TextIdentificationFrame::fieldList().front()
|
||||
: String();
|
||||
}
|
||||
|
||||
StringList UserTextIdentificationFrame::fieldList() const
|
||||
{
|
||||
// TODO: remove this function
|
||||
|
||||
return TextIdentificationFrame::fieldList();
|
||||
}
|
||||
|
||||
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())
|
||||
setDescription(String());
|
||||
|
||||
TextIdentificationFrame::setText(StringList(description()).append(fields));
|
||||
}
|
||||
|
||||
void UserTextIdentificationFrame::setDescription(const String &s)
|
||||
{
|
||||
StringList l = fieldList();
|
||||
|
||||
if(l.isEmpty())
|
||||
l.append(s);
|
||||
else
|
||||
l[0] = s;
|
||||
|
||||
TextIdentificationFrame::setText(l);
|
||||
}
|
||||
|
||||
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())
|
||||
map.insert(tagName, *it);
|
||||
return map;
|
||||
}
|
||||
|
||||
UserTextIdentificationFrame *UserTextIdentificationFrame::find(
|
||||
ID3v2::Tag *tag, const String &description) // static
|
||||
{
|
||||
FrameList l = tag->frameList("TXXX");
|
||||
for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it) {
|
||||
UserTextIdentificationFrame *f = dynamic_cast<UserTextIdentificationFrame *>(*it);
|
||||
if(f && f->description() == description)
|
||||
return f;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// UserTextIdentificationFrame private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
UserTextIdentificationFrame::UserTextIdentificationFrame(const ByteVector &data, Header *h) :
|
||||
TextIdentificationFrame(data, h)
|
||||
{
|
||||
checkFields();
|
||||
}
|
||||
|
||||
void UserTextIdentificationFrame::checkFields()
|
||||
{
|
||||
int fields = fieldList().size();
|
||||
|
||||
if(fields == 0)
|
||||
setDescription(String());
|
||||
if(fields <= 1)
|
||||
setText(String());
|
||||
}
|
||||
313
3rdparty/taglib/mpeg/id3v2/frames/textidentificationframe.h
vendored
Normal file
313
3rdparty/taglib/mpeg/id3v2/frames/textidentificationframe.h
vendored
Normal file
@@ -0,0 +1,313 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_TEXTIDENTIFICATIONFRAME_H
|
||||
#define TAGLIB_TEXTIDENTIFICATIONFRAME_H
|
||||
|
||||
#include "tstringlist.h"
|
||||
#include "tmap.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
#include "id3v2frame.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
class Tag;
|
||||
typedef Map<String, String> KeyConversionMap;
|
||||
|
||||
//! 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:
|
||||
*
|
||||
* <ul>
|
||||
* <li><b>TALB</b> Album/Movie/Show title</li>
|
||||
* <li><b>TBPM</b> BPM (beats per minute)</li>
|
||||
* <li><b>TCOM</b> Composer</li>
|
||||
* <li><b>TCON</b> Content type</li>
|
||||
* <li><b>TCOP</b> Copyright message</li>
|
||||
* <li><b>TDEN</b> Encoding time</li>
|
||||
* <li><b>TDLY</b> Playlist delay</li>
|
||||
* <li><b>TDOR</b> Original release time</li>
|
||||
* <li><b>TDRC</b> Recording time</li>
|
||||
* <li><b>TDRL</b> Release time</li>
|
||||
* <li><b>TDTG</b> Tagging time</li>
|
||||
* <li><b>TENC</b> Encoded by</li>
|
||||
* <li><b>TEXT</b> Lyricist/Text writer</li>
|
||||
* <li><b>TFLT</b> File type</li>
|
||||
* <li><b>TIPL</b> Involved people list</li>
|
||||
* <li><b>TIT1</b> Content group description</li>
|
||||
* <li><b>TIT2</b> Title/songname/content description</li>
|
||||
* <li><b>TIT3</b> Subtitle/Description refinement</li>
|
||||
* <li><b>TKEY</b> Initial key</li>
|
||||
* <li><b>TLAN</b> Language(s)</li>
|
||||
* <li><b>TLEN</b> Length</li>
|
||||
* <li><b>TMCL</b> Musician credits list</li>
|
||||
* <li><b>TMED</b> Media type</li>
|
||||
* <li><b>TMOO</b> Mood</li>
|
||||
* <li><b>TOAL</b> Original album/movie/show title</li>
|
||||
* <li><b>TOFN</b> Original filename</li>
|
||||
* <li><b>TOLY</b> Original lyricist(s)/text writer(s)</li>
|
||||
* <li><b>TOPE</b> Original artist(s)/performer(s)</li>
|
||||
* <li><b>TOWN</b> File owner/licensee</li>
|
||||
* <li><b>TPE1</b> Lead performer(s)/Soloist(s)</li>
|
||||
* <li><b>TPE2</b> Band/orchestra/accompaniment</li>
|
||||
* <li><b>TPE3</b> Conductor/performer refinement</li>
|
||||
* <li><b>TPE4</b> Interpreted, remixed, or otherwise modified by</li>
|
||||
* <li><b>TPOS</b> Part of a set</li>
|
||||
* <li><b>TPRO</b> Produced notice</li>
|
||||
* <li><b>TPUB</b> Publisher</li>
|
||||
* <li><b>TRCK</b> Track number/Position in set</li>
|
||||
* <li><b>TRSN</b> Internet radio station name</li>
|
||||
* <li><b>TRSO</b> Internet radio station owner</li>
|
||||
* <li><b>TSOA</b> Album sort order</li>
|
||||
* <li><b>TSOP</b> Performer sort order</li>
|
||||
* <li><b>TSOT</b> Title sort order</li>
|
||||
* <li><b>TSRC</b> ISRC (international standard recording code)</li>
|
||||
* <li><b>TSSE</b> Software/Hardware and settings used for encoding</li>
|
||||
* <li><b>TSST</b> Set subtitle</li>
|
||||
* </ul>
|
||||
*
|
||||
* The ID3v2 Frames document gives a description of each of these formats
|
||||
* and the expected order of strings in each. ID3v2::Header::frameID() can
|
||||
* be used to determine the frame type.
|
||||
*
|
||||
* \note If non-Latin1 compatible strings are used with this class, even if
|
||||
* the text encoding is set to Latin1, the frame will be written using UTF8
|
||||
* (with the encoding flag appropriately set in the output).
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT TextIdentificationFrame : public Frame
|
||||
{
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Construct an empty frame of type \a type. Uses \a encoding as the
|
||||
* default text encoding.
|
||||
*
|
||||
* \note In this case you must specify the text encoding as it
|
||||
* resolves the ambiguity between constructors.
|
||||
*
|
||||
* \note Please see the note in the class description regarding Latin1.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
/*!
|
||||
* Destroys this TextIdentificationFrame instance.
|
||||
*/
|
||||
virtual ~TextIdentificationFrame();
|
||||
|
||||
/*!
|
||||
* Text identification frames are a list of string fields.
|
||||
*
|
||||
* This function will accept either a StringList or a String (using the
|
||||
* StringList constructor that accepts a single String).
|
||||
*
|
||||
* \note This will not change the text encoding of the frame even if the
|
||||
* 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);
|
||||
|
||||
// Reimplementations.
|
||||
|
||||
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.
|
||||
*
|
||||
* \note Please see the note in the class description regarding Latin1.
|
||||
*
|
||||
* \see setTextEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
String::Type textEncoding() const;
|
||||
|
||||
/*!
|
||||
* Sets the text encoding to be used when rendering this frame to
|
||||
* \a encoding.
|
||||
*
|
||||
* \note Please see the note in the class description regarding Latin1.
|
||||
*
|
||||
* \see textEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
void setTextEncoding(String::Type encoding);
|
||||
|
||||
/*!
|
||||
* Returns a list of the strings in this frame.
|
||||
*/
|
||||
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();
|
||||
|
||||
PropertyMap asProperties() const;
|
||||
|
||||
protected:
|
||||
// Reimplementations.
|
||||
|
||||
virtual void parseFields(const ByteVector &data);
|
||||
virtual ByteVector renderFields() const;
|
||||
|
||||
/*!
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
TextIdentificationFrame(const ByteVector &data, Header *h);
|
||||
|
||||
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;
|
||||
/*!
|
||||
* Parses the special structure of a TMCL frame.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* This description identifies the frame and must be unique.
|
||||
*/
|
||||
|
||||
//! An ID3v2 custom text identification frame implementation
|
||||
|
||||
class TAGLIB_EXPORT UserTextIdentificationFrame : public TextIdentificationFrame
|
||||
{
|
||||
friend class FrameFactory;
|
||||
|
||||
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);
|
||||
|
||||
/*!
|
||||
* Creates a frame based on \a 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);
|
||||
|
||||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
* Returns the description for this frame.
|
||||
*/
|
||||
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);
|
||||
|
||||
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
|
||||
* separator is considered as key (compatibility with exfalso)
|
||||
* - if the above rules don't yield a valid key (e.g. containing non-ASCII
|
||||
* characters), the returned map will contain an entry "TXXX/<description>"
|
||||
* in its unsupportedData() list.
|
||||
* - The values will be copies of the fieldList().
|
||||
* - If the description() appears as value in fieldList(), it will be omitted
|
||||
* in the value list, in order to be compatible with TagLib which copies
|
||||
* the description() into the fieldList().
|
||||
*/
|
||||
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);
|
||||
|
||||
private:
|
||||
UserTextIdentificationFrame(const ByteVector &data, Header *h);
|
||||
UserTextIdentificationFrame(const TextIdentificationFrame &);
|
||||
UserTextIdentificationFrame &operator=(const UserTextIdentificationFrame &);
|
||||
|
||||
void checkFields();
|
||||
|
||||
class UserTextIdentificationFramePrivate;
|
||||
UserTextIdentificationFramePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
148
3rdparty/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.cpp
vendored
Normal file
148
3rdparty/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.cpp
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tbytevectorlist.h>
|
||||
#include <tpropertymap.h>
|
||||
#include <tdebug.h>
|
||||
|
||||
#include "id3v2tag.h"
|
||||
#include "uniquefileidentifierframe.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class UniqueFileIdentifierFrame::UniqueFileIdentifierFramePrivate
|
||||
{
|
||||
public:
|
||||
String owner;
|
||||
ByteVector identifier;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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())
|
||||
{
|
||||
d->owner = owner;
|
||||
d->identifier = id;
|
||||
}
|
||||
|
||||
UniqueFileIdentifierFrame::~UniqueFileIdentifierFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String UniqueFileIdentifierFrame::owner() const
|
||||
{
|
||||
return d->owner;
|
||||
}
|
||||
|
||||
ByteVector UniqueFileIdentifierFrame::identifier() const
|
||||
{
|
||||
return d->identifier;
|
||||
}
|
||||
|
||||
void UniqueFileIdentifierFrame::setOwner(const String &s)
|
||||
{
|
||||
d->owner = s;
|
||||
}
|
||||
|
||||
void UniqueFileIdentifierFrame::setIdentifier(const ByteVector &v)
|
||||
{
|
||||
d->identifier = v;
|
||||
}
|
||||
|
||||
String UniqueFileIdentifierFrame::toString() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
PropertyMap UniqueFileIdentifierFrame::asProperties() const
|
||||
{
|
||||
PropertyMap map;
|
||||
if(d->owner == "http://musicbrainz.org") {
|
||||
map.insert("MUSICBRAINZ_TRACKID", String(d->identifier));
|
||||
}
|
||||
else {
|
||||
map.unsupportedData().append(frameID() + String("/") + d->owner);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
UniqueFileIdentifierFrame *frame = dynamic_cast<UniqueFileIdentifierFrame *>(*it);
|
||||
if(frame && frame->owner() == o)
|
||||
return frame;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void UniqueFileIdentifierFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
if(data.size() < 1) {
|
||||
debug("An UFID frame must contain at least 1 byte.");
|
||||
return;
|
||||
}
|
||||
|
||||
int pos = 0;
|
||||
d->owner = readStringField(data, String::Latin1, &pos);
|
||||
d->identifier = data.mid(pos);
|
||||
}
|
||||
|
||||
ByteVector UniqueFileIdentifierFrame::renderFields() const
|
||||
{
|
||||
ByteVector data;
|
||||
|
||||
data.append(d->owner.data(String::Latin1));
|
||||
data.append(char(0));
|
||||
data.append(d->identifier);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
UniqueFileIdentifierFrame::UniqueFileIdentifierFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new UniqueFileIdentifierFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
123
3rdparty/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.h
vendored
Normal file
123
3rdparty/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.h
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_UNIQUEFILEIDENTIFIERFRAME
|
||||
#define TAGLIB_UNIQUEFILEIDENTIFIERFRAME
|
||||
|
||||
#include "id3v2frame.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
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
|
||||
|
||||
class TAGLIB_EXPORT UniqueFileIdentifierFrame : public ID3v2::Frame
|
||||
{
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Creates a unique file identifier frame based on \a 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);
|
||||
|
||||
/*!
|
||||
* Destroys the frame.
|
||||
*/
|
||||
~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
|
||||
* used to create the unique identifier.
|
||||
*
|
||||
* \see setOwner()
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Sets the owner of the identification scheme to \a s.
|
||||
*
|
||||
* \see owner()
|
||||
*/
|
||||
void setOwner(const String &s);
|
||||
|
||||
/*!
|
||||
* Sets the unique file identifier to \a v.
|
||||
*
|
||||
* \see identifier()
|
||||
*/
|
||||
void setIdentifier(const ByteVector &v);
|
||||
|
||||
virtual String toString() 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);
|
||||
|
||||
protected:
|
||||
virtual void parseFields(const ByteVector &data);
|
||||
virtual ByteVector renderFields() const;
|
||||
|
||||
private:
|
||||
UniqueFileIdentifierFrame(const UniqueFileIdentifierFrame &);
|
||||
UniqueFileIdentifierFrame &operator=(const UniqueFileIdentifierFrame &);
|
||||
|
||||
UniqueFileIdentifierFrame(const ByteVector &data, Header *h);
|
||||
|
||||
class UniqueFileIdentifierFramePrivate;
|
||||
UniqueFileIdentifierFramePrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
86
3rdparty/taglib/mpeg/id3v2/frames/unknownframe.cpp
vendored
Normal file
86
3rdparty/taglib/mpeg/id3v2/frames/unknownframe.cpp
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include "unknownframe.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class UnknownFrame::UnknownFramePrivate
|
||||
{
|
||||
public:
|
||||
ByteVector fieldData;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
UnknownFrame::UnknownFrame(const ByteVector &data) :
|
||||
Frame(data),
|
||||
d(new UnknownFramePrivate())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
|
||||
UnknownFrame::~UnknownFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String UnknownFrame::toString() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
ByteVector UnknownFrame::data() const
|
||||
{
|
||||
return d->fieldData;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void UnknownFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
d->fieldData = data;
|
||||
}
|
||||
|
||||
ByteVector UnknownFrame::renderFields() const
|
||||
{
|
||||
return d->fieldData;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
UnknownFrame::UnknownFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new UnknownFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
79
3rdparty/taglib/mpeg/id3v2/frames/unknownframe.h
vendored
Normal file
79
3rdparty/taglib/mpeg/id3v2/frames/unknownframe.h
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_UNKNOWNFRAME_H
|
||||
#define TAGLIB_UNKNOWNFRAME_H
|
||||
|
||||
#include "id3v2frame.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! 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
|
||||
* of rendering such \e unknown frames.
|
||||
*
|
||||
* Please note that a cleaner way of handling frame types that TagLib
|
||||
* does not understand is to subclass ID3v2::Frame and ID3v2::FrameFactory
|
||||
* to have your frame type supported through the standard ID3v2 mechanism.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT UnknownFrame : public Frame
|
||||
{
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
UnknownFrame(const ByteVector &data);
|
||||
virtual ~UnknownFrame();
|
||||
|
||||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
* Returns the field data (everything but the header) for this frame.
|
||||
*/
|
||||
ByteVector data() 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 &);
|
||||
|
||||
class UnknownFramePrivate;
|
||||
UnknownFramePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
198
3rdparty/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp
vendored
Normal file
198
3rdparty/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
|
||||
copyright : (C) 2006 by Urs Fleisch
|
||||
email : ufleisch@users.sourceforge.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include "unsynchronizedlyricsframe.h"
|
||||
#include <tbytevectorlist.h>
|
||||
#include <id3v2tag.h>
|
||||
#include <tdebug.h>
|
||||
#include <tpropertymap.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class UnsynchronizedLyricsFrame::UnsynchronizedLyricsFramePrivate
|
||||
{
|
||||
public:
|
||||
UnsynchronizedLyricsFramePrivate() : textEncoding(String::Latin1) {}
|
||||
String::Type textEncoding;
|
||||
ByteVector language;
|
||||
String description;
|
||||
String text;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(String::Type encoding) :
|
||||
Frame("USLT"),
|
||||
d(new UnsynchronizedLyricsFramePrivate())
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(const ByteVector &data) :
|
||||
Frame(data),
|
||||
d(new UnsynchronizedLyricsFramePrivate())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
|
||||
UnsynchronizedLyricsFrame::~UnsynchronizedLyricsFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String UnsynchronizedLyricsFrame::toString() const
|
||||
{
|
||||
return d->text;
|
||||
}
|
||||
|
||||
ByteVector UnsynchronizedLyricsFrame::language() const
|
||||
{
|
||||
return d->language;
|
||||
}
|
||||
|
||||
String UnsynchronizedLyricsFrame::description() const
|
||||
{
|
||||
return d->description;
|
||||
}
|
||||
|
||||
String UnsynchronizedLyricsFrame::text() const
|
||||
{
|
||||
return d->text;
|
||||
}
|
||||
|
||||
void UnsynchronizedLyricsFrame::setLanguage(const ByteVector &languageEncoding)
|
||||
{
|
||||
d->language = languageEncoding.mid(0, 3);
|
||||
}
|
||||
|
||||
void UnsynchronizedLyricsFrame::setDescription(const String &s)
|
||||
{
|
||||
d->description = s;
|
||||
}
|
||||
|
||||
void UnsynchronizedLyricsFrame::setText(const String &s)
|
||||
{
|
||||
d->text = s;
|
||||
}
|
||||
|
||||
|
||||
String::Type UnsynchronizedLyricsFrame::textEncoding() const
|
||||
{
|
||||
return d->textEncoding;
|
||||
}
|
||||
|
||||
void UnsynchronizedLyricsFrame::setTextEncoding(String::Type encoding)
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
PropertyMap UnsynchronizedLyricsFrame::asProperties() const
|
||||
{
|
||||
PropertyMap map;
|
||||
String key = description().upper();
|
||||
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
|
||||
{
|
||||
ID3v2::FrameList lyrics = tag->frameList("USLT");
|
||||
|
||||
for(ID3v2::FrameList::ConstIterator it = lyrics.begin(); it != lyrics.end(); ++it){
|
||||
UnsynchronizedLyricsFrame *frame = dynamic_cast<UnsynchronizedLyricsFrame *>(*it);
|
||||
if(frame && frame->description() == d)
|
||||
return frame;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void UnsynchronizedLyricsFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
if(data.size() < 5) {
|
||||
debug("An unsynchronized lyrics frame must contain at least 5 bytes.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->textEncoding = String::Type(data[0]);
|
||||
d->language = data.mid(1, 3);
|
||||
|
||||
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) {
|
||||
d->description = Tag::latin1StringHandler()->parse(l.front());
|
||||
d->text = Tag::latin1StringHandler()->parse(l.back());
|
||||
} else {
|
||||
d->description = String(l.front(), d->textEncoding);
|
||||
d->text = String(l.back(), d->textEncoding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector UnsynchronizedLyricsFrame::renderFields() const
|
||||
{
|
||||
StringList sl;
|
||||
sl.append(d->description);
|
||||
sl.append(d->text);
|
||||
|
||||
const String::Type encoding = checkTextEncoding(sl, d->textEncoding);
|
||||
|
||||
ByteVector v;
|
||||
|
||||
v.append(char(encoding));
|
||||
v.append(d->language.size() == 3 ? d->language : "XXX");
|
||||
v.append(d->description.data(encoding));
|
||||
v.append(textDelimiter(encoding));
|
||||
v.append(d->text.data(encoding));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new UnsynchronizedLyricsFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
179
3rdparty/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.h
vendored
Normal file
179
3rdparty/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.h
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
copyright : (C) 2006 by Urs Fleisch
|
||||
email : ufleisch@users.sourceforge.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_UNSYNCHRONIZEDLYRICSFRAME_H
|
||||
#define TAGLIB_UNSYNCHRONIZEDLYRICSFRAME_H
|
||||
|
||||
#include "id3v2frame.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! ID3v2 unsynchronized lyrics frame
|
||||
/*!
|
||||
* An implementation of ID3v2 unsynchronized lyrics.
|
||||
*/
|
||||
class TAGLIB_EXPORT UnsynchronizedLyricsFrame : public Frame
|
||||
{
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Construct an empty unsynchronized lyrics frame that will use the text encoding
|
||||
* \a encoding.
|
||||
*/
|
||||
explicit UnsynchronizedLyricsFrame(String::Type encoding = String::Latin1);
|
||||
|
||||
/*!
|
||||
* Construct a unsynchronized lyrics frame based on the data in \a data.
|
||||
*/
|
||||
explicit UnsynchronizedLyricsFrame(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Destroys this UnsynchronizedLyricsFrame instance.
|
||||
*/
|
||||
virtual ~UnsynchronizedLyricsFrame();
|
||||
|
||||
/*!
|
||||
* Returns the text of this unsynchronized lyrics frame.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
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>.
|
||||
*
|
||||
* \note Most taggers simply ignore this value.
|
||||
*
|
||||
* \see setLanguage()
|
||||
*/
|
||||
ByteVector language() const;
|
||||
|
||||
/*!
|
||||
* Returns the description of this unsynchronized lyrics frame.
|
||||
*
|
||||
* \note Most taggers simply ignore this value.
|
||||
*
|
||||
* \see setDescription()
|
||||
*/
|
||||
String description() const;
|
||||
|
||||
/*!
|
||||
* Returns the text of this unsynchronized lyrics frame.
|
||||
*
|
||||
* \see setText()
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* Sets the description of the unsynchronized lyrics frame to \a s.
|
||||
*
|
||||
* \see description()
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* 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.
|
||||
*
|
||||
* \see setTextEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
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);
|
||||
|
||||
|
||||
/*! 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()
|
||||
* attribute of the returned map.
|
||||
* - otherwise, the key will be "LYRICS:<description>"
|
||||
* - The single value will be the frame's text().
|
||||
* Note that currently the language() field is not supported by the PropertyMap
|
||||
* interface.
|
||||
*/
|
||||
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);
|
||||
|
||||
protected:
|
||||
// Reimplementations.
|
||||
|
||||
virtual void parseFields(const ByteVector &data);
|
||||
virtual ByteVector renderFields() const;
|
||||
|
||||
private:
|
||||
/*!
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
UnsynchronizedLyricsFrame(const ByteVector &data, Header *h);
|
||||
UnsynchronizedLyricsFrame(const UnsynchronizedLyricsFrame &);
|
||||
UnsynchronizedLyricsFrame &operator=(const UnsynchronizedLyricsFrame &);
|
||||
|
||||
class UnsynchronizedLyricsFramePrivate;
|
||||
UnsynchronizedLyricsFramePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
246
3rdparty/taglib/mpeg/id3v2/frames/urllinkframe.cpp
vendored
Normal file
246
3rdparty/taglib/mpeg/id3v2/frames/urllinkframe.cpp
vendored
Normal file
@@ -0,0 +1,246 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
|
||||
copyright : (C) 2006 by Urs Fleisch
|
||||
email : ufleisch@users.sourceforge.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include "urllinkframe.h"
|
||||
#include "id3v2tag.h"
|
||||
#include <tdebug.h>
|
||||
#include <tstringlist.h>
|
||||
#include <tpropertymap.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class UrlLinkFrame::UrlLinkFramePrivate
|
||||
{
|
||||
public:
|
||||
String url;
|
||||
};
|
||||
|
||||
class UserUrlLinkFrame::UserUrlLinkFramePrivate
|
||||
{
|
||||
public:
|
||||
UserUrlLinkFramePrivate() : textEncoding(String::Latin1) {}
|
||||
String::Type textEncoding;
|
||||
String description;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// UrlLinkFrame public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
UrlLinkFrame::UrlLinkFrame(const ByteVector &data) :
|
||||
Frame(data),
|
||||
d(new UrlLinkFramePrivate())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
|
||||
UrlLinkFrame::~UrlLinkFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void UrlLinkFrame::setUrl(const String &s)
|
||||
{
|
||||
d->url = s;
|
||||
}
|
||||
|
||||
String UrlLinkFrame::url() const
|
||||
{
|
||||
return d->url;
|
||||
}
|
||||
|
||||
void UrlLinkFrame::setText(const String &s)
|
||||
{
|
||||
setUrl(s);
|
||||
}
|
||||
|
||||
String UrlLinkFrame::toString() const
|
||||
{
|
||||
return url();
|
||||
}
|
||||
|
||||
PropertyMap UrlLinkFrame::asProperties() const
|
||||
{
|
||||
String key = frameIDToKey(frameID());
|
||||
PropertyMap map;
|
||||
if(key.isEmpty())
|
||||
// unknown W*** frame - this normally shouldn't happen
|
||||
map.unsupportedData().append(frameID());
|
||||
else
|
||||
map.insert(key, url());
|
||||
return map;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// UrlLinkFrame protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void UrlLinkFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
d->url = String(data);
|
||||
}
|
||||
|
||||
ByteVector UrlLinkFrame::renderFields() const
|
||||
{
|
||||
return d->url.data(String::Latin1);
|
||||
}
|
||||
|
||||
UrlLinkFrame::UrlLinkFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new UrlLinkFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// UserUrlLinkFrame public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
UserUrlLinkFrame::UserUrlLinkFrame(String::Type encoding) :
|
||||
UrlLinkFrame("WXXX"),
|
||||
d(new UserUrlLinkFramePrivate())
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
UserUrlLinkFrame::UserUrlLinkFrame(const ByteVector &data) :
|
||||
UrlLinkFrame(data),
|
||||
d(new UserUrlLinkFramePrivate())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
|
||||
UserUrlLinkFrame::~UserUrlLinkFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String UserUrlLinkFrame::toString() const
|
||||
{
|
||||
return "[" + description() + "] " + url();
|
||||
}
|
||||
|
||||
String::Type UserUrlLinkFrame::textEncoding() const
|
||||
{
|
||||
return d->textEncoding;
|
||||
}
|
||||
|
||||
void UserUrlLinkFrame::setTextEncoding(String::Type encoding)
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
String UserUrlLinkFrame::description() const
|
||||
{
|
||||
return d->description;
|
||||
}
|
||||
|
||||
void UserUrlLinkFrame::setDescription(const String &s)
|
||||
{
|
||||
d->description = s;
|
||||
}
|
||||
|
||||
PropertyMap UserUrlLinkFrame::asProperties() const
|
||||
{
|
||||
PropertyMap map;
|
||||
String key = description().upper();
|
||||
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
|
||||
{
|
||||
FrameList l = tag->frameList("WXXX");
|
||||
for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it) {
|
||||
UserUrlLinkFrame *f = dynamic_cast<UserUrlLinkFrame *>(*it);
|
||||
if(f && f->description() == description)
|
||||
return f;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// UserUrlLinkFrame protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void UserUrlLinkFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
if(data.size() < 2) {
|
||||
debug("A user URL link frame must contain at least 2 bytes.");
|
||||
return;
|
||||
}
|
||||
|
||||
int pos = 0;
|
||||
|
||||
d->textEncoding = String::Type(data[0]);
|
||||
pos += 1;
|
||||
|
||||
if(d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8) {
|
||||
int offset = data.find(textDelimiter(d->textEncoding), pos);
|
||||
if(offset < pos)
|
||||
return;
|
||||
|
||||
d->description = String(data.mid(pos, offset - pos), d->textEncoding);
|
||||
pos = offset + 1;
|
||||
}
|
||||
else {
|
||||
int len = data.mid(pos).find(textDelimiter(d->textEncoding), 0, 2);
|
||||
if(len < 0)
|
||||
return;
|
||||
|
||||
d->description = String(data.mid(pos, len), d->textEncoding);
|
||||
pos += len + 2;
|
||||
}
|
||||
|
||||
setUrl(String(data.mid(pos)));
|
||||
}
|
||||
|
||||
ByteVector UserUrlLinkFrame::renderFields() const
|
||||
{
|
||||
ByteVector v;
|
||||
|
||||
String::Type encoding = checkTextEncoding(d->description, d->textEncoding);
|
||||
|
||||
v.append(char(encoding));
|
||||
v.append(d->description.data(encoding));
|
||||
v.append(textDelimiter(encoding));
|
||||
v.append(url().data(String::Latin1));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
UserUrlLinkFrame::UserUrlLinkFrame(const ByteVector &data, Header *h) :
|
||||
UrlLinkFrame(data, h),
|
||||
d(new UserUrlLinkFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
190
3rdparty/taglib/mpeg/id3v2/frames/urllinkframe.h
vendored
Normal file
190
3rdparty/taglib/mpeg/id3v2/frames/urllinkframe.h
vendored
Normal file
@@ -0,0 +1,190 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
|
||||
copyright : (C) 2006 by Urs Fleisch
|
||||
email : ufleisch@users.sourceforge.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_URLLINKFRAME_H
|
||||
#define TAGLIB_URLLINKFRAME_H
|
||||
|
||||
#include "id3v2frame.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! ID3v2 URL frame
|
||||
/*!
|
||||
* An implementation of ID3v2 URL link frames.
|
||||
*/
|
||||
class TAGLIB_EXPORT UrlLinkFrame : public Frame
|
||||
{
|
||||
friend class FrameFactory;
|
||||
|
||||
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);
|
||||
|
||||
/*!
|
||||
* Destroys this UrlLinkFrame instance.
|
||||
*/
|
||||
virtual ~UrlLinkFrame();
|
||||
|
||||
/*!
|
||||
* Returns the URL.
|
||||
*/
|
||||
virtual String url() const;
|
||||
|
||||
/*!
|
||||
* Sets the URL to \a s.
|
||||
*/
|
||||
virtual void setUrl(const String &s);
|
||||
|
||||
// Reimplementations.
|
||||
|
||||
virtual void setText(const String &s);
|
||||
virtual String toString() const;
|
||||
PropertyMap asProperties() const;
|
||||
|
||||
protected:
|
||||
virtual void parseFields(const ByteVector &data);
|
||||
virtual ByteVector renderFields() const;
|
||||
|
||||
/*!
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
UrlLinkFrame(const ByteVector &data, Header *h);
|
||||
|
||||
private:
|
||||
UrlLinkFrame(const UrlLinkFrame &);
|
||||
UrlLinkFrame &operator=(const UrlLinkFrame &);
|
||||
|
||||
class UrlLinkFramePrivate;
|
||||
UrlLinkFramePrivate *d;
|
||||
};
|
||||
|
||||
//! 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;
|
||||
|
||||
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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* Destroys this UserUrlLinkFrame instance.
|
||||
*/
|
||||
virtual ~UserUrlLinkFrame();
|
||||
|
||||
// Reimplementations.
|
||||
|
||||
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.
|
||||
*
|
||||
* \see setTextEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* Returns the description for this frame.
|
||||
*/
|
||||
String description() const;
|
||||
|
||||
/*!
|
||||
* Sets the description of the frame to \a s. \a s must be unique.
|
||||
*/
|
||||
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".
|
||||
* - otherwise, if description() is not a valid key (e.g. containing non-ASCII
|
||||
* characters), the returned map will contain an entry "WXXX/<description>"
|
||||
* in its unsupportedData() list.
|
||||
*/
|
||||
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);
|
||||
|
||||
protected:
|
||||
virtual void parseFields(const ByteVector &data);
|
||||
virtual ByteVector renderFields() const;
|
||||
|
||||
/*!
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
UserUrlLinkFrame(const ByteVector &data, Header *h);
|
||||
|
||||
private:
|
||||
UserUrlLinkFrame(const UserUrlLinkFrame &);
|
||||
UserUrlLinkFrame &operator=(const UserUrlLinkFrame &);
|
||||
|
||||
class UserUrlLinkFramePrivate;
|
||||
UserUrlLinkFramePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
1660
3rdparty/taglib/mpeg/id3v2/id3v2.2.0.txt
vendored
Normal file
1660
3rdparty/taglib/mpeg/id3v2/id3v2.2.0.txt
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2022
3rdparty/taglib/mpeg/id3v2/id3v2.3.0.txt
vendored
Normal file
2022
3rdparty/taglib/mpeg/id3v2/id3v2.3.0.txt
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1734
3rdparty/taglib/mpeg/id3v2/id3v2.4.0-frames.txt
vendored
Normal file
1734
3rdparty/taglib/mpeg/id3v2/id3v2.4.0-frames.txt
vendored
Normal file
File diff suppressed because it is too large
Load Diff
733
3rdparty/taglib/mpeg/id3v2/id3v2.4.0-structure.txt
vendored
Normal file
733
3rdparty/taglib/mpeg/id3v2/id3v2.4.0-structure.txt
vendored
Normal file
@@ -0,0 +1,733 @@
|
||||
|
||||
Informal standard M. Nilsson
|
||||
Document: id3v2.4.0-structure.txt 16 September 2001
|
||||
|
||||
|
||||
ID3 tag version 2.4.0 - Main Structure
|
||||
|
||||
Status of this document
|
||||
|
||||
This document is an informal standard and replaces the ID3v2.3.0
|
||||
standard [ID3v2]. A formal standard will use another revision number
|
||||
even if the content is identical to document. The contents in this
|
||||
document may change for clarifications but never for added or altered
|
||||
functionallity.
|
||||
|
||||
Distribution of this document is unlimited.
|
||||
|
||||
|
||||
Abstract
|
||||
|
||||
This document describes the main structure of ID3v2.4.0, which is a
|
||||
revised version of the ID3v2 informal standard [ID3v2] version
|
||||
2.3.0. The ID3v2 offers a flexible way of storing audio meta
|
||||
information within the audio file itself. The information may be
|
||||
technical information, such as equalisation curves, as well as
|
||||
title, performer, copyright etc.
|
||||
|
||||
ID3v2.4.0 is meant to be as close as possible to ID3v2.3.0 in order
|
||||
to allow for implementations to be revised as easily as possible.
|
||||
|
||||
|
||||
1. Table of contents
|
||||
|
||||
Status of this document
|
||||
Abstract
|
||||
1. Table of contents
|
||||
2. Conventions in this document
|
||||
2. Standard overview
|
||||
3. ID3v2 overview
|
||||
3.1. ID3v2 header
|
||||
3.2. ID3v2 extended header
|
||||
3.3. Padding
|
||||
3.4. ID3v2 footer
|
||||
4. ID3v2 frames overview
|
||||
4.1. Frame header flags
|
||||
4.1.1. Frame status flags
|
||||
4.1.2. Frame format flags
|
||||
5. Tag location
|
||||
6. Unsynchronisation
|
||||
6.1. The unsynchronisation scheme
|
||||
6.2. Synchsafe integers
|
||||
7. Copyright
|
||||
8. References
|
||||
9. Author's Address
|
||||
|
||||
|
||||
2. Conventions in this document
|
||||
|
||||
Text within "" is a text string exactly as it appears in a tag.
|
||||
Numbers preceded with $ are hexadecimal and numbers preceded with %
|
||||
are binary. $xx is used to indicate a byte with unknown content. %x
|
||||
is used to indicate a bit with unknown content. The most significant
|
||||
bit (MSB) of a byte is called 'bit 7' and the least significant bit
|
||||
(LSB) is called 'bit 0'.
|
||||
|
||||
A tag is the whole tag described in this document. A frame is a block
|
||||
of information in the tag. The tag consists of a header, frames and
|
||||
optional padding. A field is a piece of information; one value, a
|
||||
string etc. A numeric string is a string that consists of the
|
||||
characters "0123456789" only.
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
|
||||
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
|
||||
document are to be interpreted as described in RFC 2119 [KEYWORDS].
|
||||
|
||||
|
||||
3. ID3v2 overview
|
||||
|
||||
ID3v2 is a general tagging format for audio, which makes it possible
|
||||
to store meta data about the audio inside the audio file itself. The
|
||||
ID3 tag described in this document is mainly targeted at files
|
||||
encoded with MPEG-1/2 layer I, MPEG-1/2 layer II, MPEG-1/2 layer III
|
||||
and MPEG-2.5, but may work with other types of encoded audio or as a
|
||||
stand alone format for audio meta data.
|
||||
|
||||
ID3v2 is designed to be as flexible and expandable as possible to
|
||||
meet new meta information needs that might arise. To achieve that
|
||||
ID3v2 is constructed as a container for several information blocks,
|
||||
called frames, whose format need not be known to the software that
|
||||
encounters them. At the start of every frame is an unique and
|
||||
predefined identifier, a size descriptor that allows software to skip
|
||||
unknown frames and a flags field. The flags describes encoding
|
||||
details and if the frame should remain in the tag, should it be
|
||||
unknown to the software, if the file is altered.
|
||||
|
||||
The bitorder in ID3v2 is most significant bit first (MSB). The
|
||||
byteorder in multibyte numbers is most significant byte first (e.g.
|
||||
$12345678 would be encoded $12 34 56 78), also known as big endian
|
||||
and network byte order.
|
||||
|
||||
Overall tag structure:
|
||||
|
||||
+-----------------------------+
|
||||
| Header (10 bytes) |
|
||||
+-----------------------------+
|
||||
| Extended Header |
|
||||
| (variable length, OPTIONAL) |
|
||||
+-----------------------------+
|
||||
| Frames (variable length) |
|
||||
+-----------------------------+
|
||||
| Padding |
|
||||
| (variable length, OPTIONAL) |
|
||||
+-----------------------------+
|
||||
| Footer (10 bytes, OPTIONAL) |
|
||||
+-----------------------------+
|
||||
|
||||
In general, padding and footer are mutually exclusive. See details in
|
||||
sections 3.3, 3.4 and 5.
|
||||
|
||||
|
||||
3.1. ID3v2 header
|
||||
|
||||
The first part of the ID3v2 tag is the 10 byte tag header, laid out
|
||||
as follows:
|
||||
|
||||
ID3v2/file identifier "ID3"
|
||||
ID3v2 version $04 00
|
||||
ID3v2 flags %abcd0000
|
||||
ID3v2 size 4 * %0xxxxxxx
|
||||
|
||||
The first three bytes of the tag are always "ID3", to indicate that
|
||||
this is an ID3v2 tag, directly followed by the two version bytes. The
|
||||
first byte of ID3v2 version is its major version, while the second
|
||||
byte is its revision number. In this case this is ID3v2.4.0. All
|
||||
revisions are backwards compatible while major versions are not. If
|
||||
software with ID3v2.4.0 and below support should encounter version
|
||||
five or higher it should simply ignore the whole tag. Version or
|
||||
revision will never be $FF.
|
||||
|
||||
The version is followed by the ID3v2 flags field, of which currently
|
||||
four flags are used.
|
||||
|
||||
|
||||
a - Unsynchronisation
|
||||
|
||||
Bit 7 in the 'ID3v2 flags' indicates whether or not
|
||||
unsynchronisation is applied on all frames (see section 6.1 for
|
||||
details); a set bit indicates usage.
|
||||
|
||||
|
||||
b - Extended header
|
||||
|
||||
The second bit (bit 6) indicates whether or not the header is
|
||||
followed by an extended header. The extended header is described in
|
||||
section 3.2. A set bit indicates the presence of an extended
|
||||
header.
|
||||
|
||||
|
||||
c - Experimental indicator
|
||||
|
||||
The third bit (bit 5) is used as an 'experimental indicator'. This
|
||||
flag SHALL always be set when the tag is in an experimental stage.
|
||||
|
||||
|
||||
d - Footer present
|
||||
|
||||
Bit 4 indicates that a footer (section 3.4) is present at the very
|
||||
end of the tag. A set bit indicates the presence of a footer.
|
||||
|
||||
|
||||
All the other flags MUST be cleared. If one of these undefined flags
|
||||
are set, the tag might not be readable for a parser that does not
|
||||
know the flags function.
|
||||
|
||||
The ID3v2 tag size is stored as a 32 bit synchsafe integer (section
|
||||
6.2), making a total of 28 effective bits (representing up to 256MB).
|
||||
|
||||
The ID3v2 tag size is the sum of the byte length of the extended
|
||||
header, the padding and the frames after unsynchronisation. If a
|
||||
footer is present this equals to ('total size' - 20) bytes, otherwise
|
||||
('total size' - 10) bytes.
|
||||
|
||||
An ID3v2 tag can be detected with the following pattern:
|
||||
$49 44 33 yy yy xx zz zz zz zz
|
||||
Where yy is less than $FF, xx is the 'flags' byte and zz is less than
|
||||
$80.
|
||||
|
||||
|
||||
3.2. Extended header
|
||||
|
||||
The extended header contains information that can provide further
|
||||
insight in the structure of the tag, but is not vital to the correct
|
||||
parsing of the tag information; hence the extended header is
|
||||
optional.
|
||||
|
||||
Extended header size 4 * %0xxxxxxx
|
||||
Number of flag bytes $01
|
||||
Extended Flags $xx
|
||||
|
||||
Where the 'Extended header size' is the size of the whole extended
|
||||
header, stored as a 32 bit synchsafe integer. An extended header can
|
||||
thus never have a size of fewer than six bytes.
|
||||
|
||||
The extended flags field, with its size described by 'number of flag
|
||||
bytes', is defined as:
|
||||
|
||||
%0bcd0000
|
||||
|
||||
Each flag that is set in the extended header has data attached, which
|
||||
comes in the order in which the flags are encountered (i.e. the data
|
||||
for flag 'b' comes before the data for flag 'c'). Unset flags cannot
|
||||
have any attached data. All unknown flags MUST be unset and their
|
||||
corresponding data removed when a tag is modified.
|
||||
|
||||
Every set flag's data starts with a length byte, which contains a
|
||||
value between 0 and 127 ($00 - $7f), followed by data that has the
|
||||
field length indicated by the length byte. If a flag has no attached
|
||||
data, the value $00 is used as length byte.
|
||||
|
||||
|
||||
b - Tag is an update
|
||||
|
||||
If this flag is set, the present tag is an update of a tag found
|
||||
earlier in the present file or stream. If frames defined as unique
|
||||
are found in the present tag, they are to override any
|
||||
corresponding ones found in the earlier tag. This flag has no
|
||||
corresponding data.
|
||||
|
||||
Flag data length $00
|
||||
|
||||
c - CRC data present
|
||||
|
||||
If this flag is set, a CRC-32 [ISO-3309] data is included in the
|
||||
extended header. The CRC is calculated on all the data between the
|
||||
header and footer as indicated by the header's tag length field,
|
||||
minus the extended header. Note that this includes the padding (if
|
||||
there is any), but excludes the footer. The CRC-32 is stored as an
|
||||
35 bit synchsafe integer, leaving the upper four bits always
|
||||
zeroed.
|
||||
|
||||
Flag data length $05
|
||||
Total frame CRC 5 * %0xxxxxxx
|
||||
|
||||
d - Tag restrictions
|
||||
|
||||
For some applications it might be desired to restrict a tag in more
|
||||
ways than imposed by the ID3v2 specification. Note that the
|
||||
presence of these restrictions does not affect how the tag is
|
||||
decoded, merely how it was restricted before encoding. If this flag
|
||||
is set the tag is restricted as follows:
|
||||
|
||||
Flag data length $01
|
||||
Restrictions %ppqrrstt
|
||||
|
||||
p - Tag size restrictions
|
||||
|
||||
00 No more than 128 frames and 1 MB total tag size.
|
||||
01 No more than 64 frames and 128 KB total tag size.
|
||||
10 No more than 32 frames and 40 KB total tag size.
|
||||
11 No more than 32 frames and 4 KB total tag size.
|
||||
|
||||
q - Text encoding restrictions
|
||||
|
||||
0 No restrictions
|
||||
1 Strings are only encoded with ISO-8859-1 [ISO-8859-1] or
|
||||
UTF-8 [UTF-8].
|
||||
|
||||
r - Text fields size restrictions
|
||||
|
||||
00 No restrictions
|
||||
01 No string is longer than 1024 characters.
|
||||
10 No string is longer than 128 characters.
|
||||
11 No string is longer than 30 characters.
|
||||
|
||||
Note that nothing is said about how many bytes is used to
|
||||
represent those characters, since it is encoding dependent. If a
|
||||
text frame consists of more than one string, the sum of the
|
||||
strungs is restricted as stated.
|
||||
|
||||
s - Image encoding restrictions
|
||||
|
||||
0 No restrictions
|
||||
1 Images are encoded only with PNG [PNG] or JPEG [JFIF].
|
||||
|
||||
t - Image size restrictions
|
||||
|
||||
00 No restrictions
|
||||
01 All images are 256x256 pixels or smaller.
|
||||
10 All images are 64x64 pixels or smaller.
|
||||
11 All images are exactly 64x64 pixels, unless required
|
||||
otherwise.
|
||||
|
||||
|
||||
3.3. Padding
|
||||
|
||||
It is OPTIONAL to include padding after the final frame (at the end
|
||||
of the ID3 tag), making the size of all the frames together smaller
|
||||
than the size given in the tag header. A possible purpose of this
|
||||
padding is to allow for adding a few additional frames or enlarge
|
||||
existing frames within the tag without having to rewrite the entire
|
||||
file. The value of the padding bytes must be $00. A tag MUST NOT have
|
||||
any padding between the frames or between the tag header and the
|
||||
frames. Furthermore it MUST NOT have any padding when a tag footer is
|
||||
added to the tag.
|
||||
|
||||
|
||||
3.4. ID3v2 footer
|
||||
|
||||
To speed up the process of locating an ID3v2 tag when searching from
|
||||
the end of a file, a footer can be added to the tag. It is REQUIRED
|
||||
to add a footer to an appended tag, i.e. a tag located after all
|
||||
audio data. The footer is a copy of the header, but with a different
|
||||
identifier.
|
||||
|
||||
ID3v2 identifier "3DI"
|
||||
ID3v2 version $04 00
|
||||
ID3v2 flags %abcd0000
|
||||
ID3v2 size 4 * %0xxxxxxx
|
||||
|
||||
|
||||
4. ID3v2 frame overview
|
||||
|
||||
All ID3v2 frames consists of one frame header followed by one or more
|
||||
fields containing the actual information. The header is always 10
|
||||
bytes and laid out as follows:
|
||||
|
||||
Frame ID $xx xx xx xx (four characters)
|
||||
Size 4 * %0xxxxxxx
|
||||
Flags $xx xx
|
||||
|
||||
The frame ID is made out of the characters capital A-Z and 0-9.
|
||||
Identifiers beginning with "X", "Y" and "Z" are for experimental
|
||||
frames and free for everyone to use, without the need to set the
|
||||
experimental bit in the tag header. Bear in mind that someone else
|
||||
might have used the same identifier as you. All other identifiers are
|
||||
either used or reserved for future use.
|
||||
|
||||
The frame ID is followed by a size descriptor containing the size of
|
||||
the data in the final frame, after encryption, compression and
|
||||
unsynchronisation. The size is excluding the frame header ('total
|
||||
frame size' - 10 bytes) and stored as a 32 bit synchsafe integer.
|
||||
|
||||
In the frame header the size descriptor is followed by two flag
|
||||
bytes. These flags are described in section 4.1.
|
||||
|
||||
There is no fixed order of the frames' appearance in the tag,
|
||||
although it is desired that the frames are arranged in order of
|
||||
significance concerning the recognition of the file. An example of
|
||||
such order: UFID, TIT2, MCDI, TRCK ...
|
||||
|
||||
A tag MUST contain at least one frame. A frame must be at least 1
|
||||
byte big, excluding the header.
|
||||
|
||||
If nothing else is said, strings, including numeric strings and URLs
|
||||
[URL], are represented as ISO-8859-1 [ISO-8859-1] characters in the
|
||||
range $20 - $FF. Such strings are represented in frame descriptions
|
||||
as <text string>, or <full text string> if newlines are allowed. If
|
||||
nothing else is said newline character is forbidden. In ISO-8859-1 a
|
||||
newline is represented, when allowed, with $0A only.
|
||||
|
||||
Frames that allow different types of text encoding contains a text
|
||||
encoding description byte. Possible encodings:
|
||||
|
||||
$00 ISO-8859-1 [ISO-8859-1]. Terminated with $00.
|
||||
$01 UTF-16 [UTF-16] encoded Unicode [UNICODE] with BOM. All
|
||||
strings in the same frame SHALL have the same byteorder.
|
||||
Terminated with $00 00.
|
||||
$02 UTF-16BE [UTF-16] encoded Unicode [UNICODE] without BOM.
|
||||
Terminated with $00 00.
|
||||
$03 UTF-8 [UTF-8] encoded Unicode [UNICODE]. Terminated with $00.
|
||||
|
||||
Strings dependent on encoding are represented in frame descriptions
|
||||
as <text string according to encoding>, or <full text string
|
||||
according to encoding> if newlines are allowed. Any empty strings of
|
||||
type $01 which are NULL-terminated may have the Unicode BOM followed
|
||||
by a Unicode NULL ($FF FE 00 00 or $FE FF 00 00).
|
||||
|
||||
The timestamp fields are based on a subset of ISO 8601. When being as
|
||||
precise as possible the format of a time string is
|
||||
yyyy-MM-ddTHH:mm:ss (year, "-", month, "-", day, "T", hour (out of
|
||||
24), ":", minutes, ":", seconds), but the precision may be reduced by
|
||||
removing as many time indicators as wanted. Hence valid timestamps
|
||||
are
|
||||
yyyy, yyyy-MM, yyyy-MM-dd, yyyy-MM-ddTHH, yyyy-MM-ddTHH:mm and
|
||||
yyyy-MM-ddTHH:mm:ss. All time stamps are UTC. For durations, use
|
||||
the slash character as described in 8601, and for multiple non-
|
||||
contiguous dates, use multiple strings, if allowed by the frame
|
||||
definition.
|
||||
|
||||
The three byte language field, present in several frames, is used to
|
||||
describe the language of the frame's content, according to ISO-639-2
|
||||
[ISO-639-2]. The language should be represented in lower case. If the
|
||||
language is not known the string "XXX" should be used.
|
||||
|
||||
All URLs [URL] MAY be relative, e.g. "picture.png", "../doc.txt".
|
||||
|
||||
If a frame is longer than it should be, e.g. having more fields than
|
||||
specified in this document, that indicates that additions to the
|
||||
frame have been made in a later version of the ID3v2 standard. This
|
||||
is reflected by the revision number in the header of the tag.
|
||||
|
||||
|
||||
4.1. Frame header flags
|
||||
|
||||
In the frame header the size descriptor is followed by two flag
|
||||
bytes. All unused flags MUST be cleared. The first byte is for
|
||||
'status messages' and the second byte is a format description. If an
|
||||
unknown flag is set in the first byte the frame MUST NOT be changed
|
||||
without that bit cleared. If an unknown flag is set in the second
|
||||
byte the frame is likely to not be readable. Some flags in the second
|
||||
byte indicates that extra information is added to the header. These
|
||||
fields of extra information is ordered as the flags that indicates
|
||||
them. The flags field is defined as follows (l and o left out because
|
||||
ther resemblence to one and zero):
|
||||
|
||||
%0abc0000 %0h00kmnp
|
||||
|
||||
Some frame format flags indicate that additional information fields
|
||||
are added to the frame. This information is added after the frame
|
||||
header and before the frame data in the same order as the flags that
|
||||
indicates them. I.e. the four bytes of decompressed size will precede
|
||||
the encryption method byte. These additions affects the 'frame size'
|
||||
field, but are not subject to encryption or compression.
|
||||
|
||||
The default status flags setting for a frame is, unless stated
|
||||
otherwise, 'preserved if tag is altered' and 'preserved if file is
|
||||
altered', i.e. %00000000.
|
||||
|
||||
|
||||
4.1.1. Frame status flags
|
||||
|
||||
a - Tag alter preservation
|
||||
|
||||
This flag tells the tag parser what to do with this frame if it is
|
||||
unknown and the tag is altered in any way. This applies to all
|
||||
kinds of alterations, including adding more padding and reordering
|
||||
the frames.
|
||||
|
||||
0 Frame should be preserved.
|
||||
1 Frame should be discarded.
|
||||
|
||||
|
||||
b - File alter preservation
|
||||
|
||||
This flag tells the tag parser what to do with this frame if it is
|
||||
unknown and the file, excluding the tag, is altered. This does not
|
||||
apply when the audio is completely replaced with other audio data.
|
||||
|
||||
0 Frame should be preserved.
|
||||
1 Frame should be discarded.
|
||||
|
||||
|
||||
c - Read only
|
||||
|
||||
This flag, if set, tells the software that the contents of this
|
||||
frame are intended to be read only. Changing the contents might
|
||||
break something, e.g. a signature. If the contents are changed,
|
||||
without knowledge of why the frame was flagged read only and
|
||||
without taking the proper means to compensate, e.g. recalculating
|
||||
the signature, the bit MUST be cleared.
|
||||
|
||||
|
||||
4.1.2. Frame format flags
|
||||
|
||||
h - Grouping identity
|
||||
|
||||
This flag indicates whether or not this frame belongs in a group
|
||||
with other frames. If set, a group identifier byte is added to the
|
||||
frame. Every frame with the same group identifier belongs to the
|
||||
same group.
|
||||
|
||||
0 Frame does not contain group information
|
||||
1 Frame contains group information
|
||||
|
||||
|
||||
k - Compression
|
||||
|
||||
This flag indicates whether or not the frame is compressed.
|
||||
A 'Data Length Indicator' byte MUST be included in the frame.
|
||||
|
||||
0 Frame is not compressed.
|
||||
1 Frame is compressed using zlib [zlib] deflate method.
|
||||
If set, this requires the 'Data Length Indicator' bit
|
||||
to be set as well.
|
||||
|
||||
|
||||
m - Encryption
|
||||
|
||||
This flag indicates whether or not the frame is encrypted. If set,
|
||||
one byte indicating with which method it was encrypted will be
|
||||
added to the frame. See description of the ENCR frame for more
|
||||
information about encryption method registration. Encryption
|
||||
should be done after compression. Whether or not setting this flag
|
||||
requires the presence of a 'Data Length Indicator' depends on the
|
||||
specific algorithm used.
|
||||
|
||||
0 Frame is not encrypted.
|
||||
1 Frame is encrypted.
|
||||
|
||||
n - Unsynchronisation
|
||||
|
||||
This flag indicates whether or not unsynchronisation was applied
|
||||
to this frame. See section 6 for details on unsynchronisation.
|
||||
If this flag is set all data from the end of this header to the
|
||||
end of this frame has been unsynchronised. Although desirable, the
|
||||
presence of a 'Data Length Indicator' is not made mandatory by
|
||||
unsynchronisation.
|
||||
|
||||
0 Frame has not been unsynchronised.
|
||||
1 Frame has been unsyrchronised.
|
||||
|
||||
p - Data length indicator
|
||||
|
||||
This flag indicates that a data length indicator has been added to
|
||||
the frame. The data length indicator is the value one would write
|
||||
as the 'Frame length' if all of the frame format flags were
|
||||
zeroed, represented as a 32 bit synchsafe integer.
|
||||
|
||||
0 There is no Data Length Indicator.
|
||||
1 A data length Indicator has been added to the frame.
|
||||
|
||||
|
||||
5. Tag location
|
||||
|
||||
The default location of an ID3v2 tag is prepended to the audio so
|
||||
that players can benefit from the information when the data is
|
||||
streamed. It is however possible to append the tag, or make a
|
||||
prepend/append combination. When deciding upon where an unembedded
|
||||
tag should be located, the following order of preference SHOULD be
|
||||
considered.
|
||||
|
||||
1. Prepend the tag.
|
||||
|
||||
2. Prepend a tag with all vital information and add a second tag at
|
||||
the end of the file, before tags from other tagging systems. The
|
||||
first tag is required to have a SEEK frame.
|
||||
|
||||
3. Add a tag at the end of the file, before tags from other tagging
|
||||
systems.
|
||||
|
||||
In case 2 and 3 the tag can simply be appended if no other known tags
|
||||
are present. The suggested method to find ID3v2 tags are:
|
||||
|
||||
1. Look for a prepended tag using the pattern found in section 3.1.
|
||||
|
||||
2. If a SEEK frame was found, use its values to guide further
|
||||
searching.
|
||||
|
||||
3. Look for a tag footer, scanning from the back of the file.
|
||||
|
||||
For every new tag that is found, the old tag should be discarded
|
||||
unless the update flag in the extended header (section 3.2) is set.
|
||||
|
||||
|
||||
6. Unsynchronisation
|
||||
|
||||
The only purpose of unsynchronisation is to make the ID3v2 tag as
|
||||
compatible as possible with existing software and hardware. There is
|
||||
no use in 'unsynchronising' tags if the file is only to be processed
|
||||
only by ID3v2 aware software and hardware. Unsynchronisation is only
|
||||
useful with tags in MPEG 1/2 layer I, II and III, MPEG 2.5 and AAC
|
||||
files.
|
||||
|
||||
|
||||
6.1. The unsynchronisation scheme
|
||||
|
||||
Whenever a false synchronisation is found within the tag, one zeroed
|
||||
byte is inserted after the first false synchronisation byte. The
|
||||
format of synchronisations that should be altered by ID3 encoders is
|
||||
as follows:
|
||||
|
||||
%11111111 111xxxxx
|
||||
|
||||
and should be replaced with:
|
||||
|
||||
%11111111 00000000 111xxxxx
|
||||
|
||||
This has the side effect that all $FF 00 combinations have to be
|
||||
altered, so they will not be affected by the decoding process.
|
||||
Therefore all the $FF 00 combinations have to be replaced with the
|
||||
$FF 00 00 combination during the unsynchronisation.
|
||||
|
||||
To indicate usage of the unsynchronisation, the unsynchronisation
|
||||
flag in the frame header should be set. This bit MUST be set if the
|
||||
frame was altered by the unsynchronisation and SHOULD NOT be set if
|
||||
unaltered. If all frames in the tag are unsynchronised the
|
||||
unsynchronisation flag in the tag header SHOULD be set. It MUST NOT
|
||||
be set if the tag has a frame which is not unsynchronised.
|
||||
|
||||
Assume the first byte of the audio to be $FF. The special case when
|
||||
the last byte of the last frame is $FF and no padding nor footer is
|
||||
used will then introduce a false synchronisation. This can be solved
|
||||
by adding a footer, adding padding or unsynchronising the frame and
|
||||
add $00 to the end of the frame data, thus adding more byte to the
|
||||
frame size than a normal unsynchronisation would. Although not
|
||||
preferred, it is allowed to apply the last method on all frames
|
||||
ending with $FF.
|
||||
|
||||
It is preferred that the tag is either completely unsynchronised or
|
||||
not unsynchronised at all. A completely unsynchronised tag has no
|
||||
false synchonisations in it, as defined above, and does not end with
|
||||
$FF. A completely non-unsynchronised tag contains no unsynchronised
|
||||
frames, and thus the unsynchronisation flag in the header is cleared.
|
||||
|
||||
Do bear in mind, that if compression or encryption is used, the
|
||||
unsynchronisation scheme MUST be applied afterwards. When decoding an
|
||||
unsynchronised frame, the unsynchronisation scheme MUST be reversed
|
||||
first, encryption and decompression afterwards.
|
||||
|
||||
|
||||
6.2. Synchsafe integers
|
||||
|
||||
In some parts of the tag it is inconvenient to use the
|
||||
unsychronisation scheme because the size of unsynchronised data is
|
||||
not known in advance, which is particularly problematic with size
|
||||
descriptors. The solution in ID3v2 is to use synchsafe integers, in
|
||||
which there can never be any false synchs. Synchsafe integers are
|
||||
integers that keep its highest bit (bit 7) zeroed, making seven bits
|
||||
out of eight available. Thus a 32 bit synchsafe integer can store 28
|
||||
bits of information.
|
||||
|
||||
Example:
|
||||
|
||||
255 (%11111111) encoded as a 16 bit synchsafe integer is 383
|
||||
(%00000001 01111111).
|
||||
|
||||
|
||||
7. Copyright
|
||||
|
||||
Copyright (C) Martin Nilsson 2000. All Rights Reserved.
|
||||
|
||||
This document and translations of it may be copied and furnished to
|
||||
others, and derivative works that comment on or otherwise explain it
|
||||
or assist in its implementation may be prepared, copied, published
|
||||
and distributed, in whole or in part, without restriction of any
|
||||
kind, provided that a reference to this document is included on all
|
||||
such copies and derivative works. However, this document itself may
|
||||
not be modified in any way and reissued as the original document.
|
||||
|
||||
The limited permissions granted above are perpetual and will not be
|
||||
revoked.
|
||||
|
||||
This document and the information contained herein is provided on an
|
||||
'AS IS' basis and THE AUTHORS DISCLAIMS ALL WARRANTIES, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
|
||||
THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
|
||||
8. References
|
||||
|
||||
[ID3v2] Martin Nilsson, 'ID3v2 informal standard'.
|
||||
|
||||
<url:http://www.id3.org/id3v2.3.0.txt>
|
||||
|
||||
[ISO-639-2] ISO/FDIS 639-2.
|
||||
'Codes for the representation of names of languages, Part 2: Alpha-3
|
||||
code.' Technical committee / subcommittee: TC 37 / SC 2
|
||||
|
||||
[ISO-3309] ISO 3309
|
||||
'Information Processing Systems--Data Communication High-Level Data
|
||||
Link Control Procedure--Frame Structure', IS 3309, October 1984, 3rd
|
||||
Edition.
|
||||
|
||||
[ISO-8859-1] ISO/IEC DIS 8859-1.
|
||||
'8-bit single-byte coded graphic character sets, Part 1: Latin
|
||||
alphabet No. 1.' Technical committee / subcommittee: JTC 1 / SC 2
|
||||
|
||||
[JFIF] 'JPEG File Interchange Format, version 1.02'
|
||||
|
||||
<url:http://www.w3.org/Graphics/JPEG/jfif.txt>
|
||||
|
||||
[KEYWORDS] S. Bradner, 'Key words for use in RFCs to Indicate
|
||||
Requirement Levels', RFC 2119, March 1997.
|
||||
|
||||
<url:ftp://ftp.isi.edu/in-notes/rfc2119.txt>
|
||||
|
||||
[MPEG] ISO/IEC 11172-3:1993.
|
||||
'Coding of moving pictures and associated audio for digital storage
|
||||
media at up to about 1,5 Mbit/s, Part 3: Audio.'
|
||||
Technical committee / subcommittee: JTC 1 / SC 29
|
||||
and
|
||||
ISO/IEC 13818-3:1995
|
||||
'Generic coding of moving pictures and associated audio information,
|
||||
Part 3: Audio.'
|
||||
Technical committee / subcommittee: JTC 1 / SC 29
|
||||
and
|
||||
ISO/IEC DIS 13818-3
|
||||
'Generic coding of moving pictures and associated audio information,
|
||||
Part 3: Audio (Revision of ISO/IEC 13818-3:1995)'
|
||||
|
||||
[PNG] 'Portable Network Graphics, version 1.0'
|
||||
|
||||
<url:http://www.w3.org/TR/REC-png-multi.html>
|
||||
|
||||
[UNICODE] The Unicode Consortium,
|
||||
'The Unicode Standard Version 3.0', ISBN 0-201-61633-5.
|
||||
|
||||
<url:http://www.unicode.org/unicode/standard/versions/Unicode3.0.htm>
|
||||
|
||||
[URL] T. Berners-Lee, L. Masinter & M. McCahill, 'Uniform Resource
|
||||
Locators (URL)', RFC 1738, December 1994.
|
||||
|
||||
<url:ftp://ftp.isi.edu/in-notes/rfc1738.txt>
|
||||
|
||||
[UTF-8] F. Yergeau, 'UTF-8, a transformation format of ISO 10646',
|
||||
RFC 2279, January 1998.
|
||||
|
||||
<url:ftp://ftp.isi.edu/in-notes/rfc2279.txt>
|
||||
|
||||
[UTF-16] F. Yergeau, 'UTF-16, an encoding of ISO 10646', RFC 2781,
|
||||
February 2000.
|
||||
|
||||
<url:ftp://ftp.isi.edu/in-notes/rfc2781.txt>
|
||||
|
||||
[ZLIB] P. Deutsch, Aladdin Enterprises & J-L. Gailly, 'ZLIB
|
||||
Compressed Data Format Specification version 3.3', RFC 1950,
|
||||
May 1996.
|
||||
|
||||
<url:ftp://ftp.isi.edu/in-notes/rfc1950.txt>
|
||||
|
||||
|
||||
9. Author's Address
|
||||
|
||||
Written by
|
||||
|
||||
Martin Nilsson
|
||||
Rydsvägen 246 C. 30
|
||||
SE-584 34 Linköping
|
||||
Sweden
|
||||
|
||||
Email: nilsson@id3.org
|
||||
|
||||
71
3rdparty/taglib/mpeg/id3v2/id3v2extendedheader.cpp
vendored
Normal file
71
3rdparty/taglib/mpeg/id3v2/id3v2extendedheader.cpp
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include "id3v2extendedheader.h"
|
||||
#include "id3v2synchdata.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class ExtendedHeader::ExtendedHeaderPrivate
|
||||
{
|
||||
public:
|
||||
ExtendedHeaderPrivate() : size(0) {}
|
||||
|
||||
unsigned int size;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ExtendedHeader::ExtendedHeader() :
|
||||
d(new ExtendedHeaderPrivate())
|
||||
{
|
||||
}
|
||||
|
||||
ExtendedHeader::~ExtendedHeader()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
unsigned int ExtendedHeader::size() const
|
||||
{
|
||||
return d->size;
|
||||
}
|
||||
|
||||
void ExtendedHeader::setData(const ByteVector &data)
|
||||
{
|
||||
parse(data);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ExtendedHeader::parse(const ByteVector &data)
|
||||
{
|
||||
d->size = SynchData::toUInt(data.mid(0, 4)); // (structure 3.2 "Extended header size")
|
||||
}
|
||||
93
3rdparty/taglib/mpeg/id3v2/id3v2extendedheader.h
vendored
Normal file
93
3rdparty/taglib/mpeg/id3v2/id3v2extendedheader.h
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_ID3V2EXTENDEDHEADER_H
|
||||
#define TAGLIB_ID3V2EXTENDEDHEADER_H
|
||||
|
||||
#include "taglib_export.h"
|
||||
#include "tbytevector.h"
|
||||
#include "taglib.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! ID3v2 extended header implementation
|
||||
|
||||
/*!
|
||||
* This class implements ID3v2 extended headers. It attempts to follow,
|
||||
* both semantically and programatically, the structure specified in
|
||||
* the ID3v2 standard. The API is based on the properties of ID3v2 extended
|
||||
* headers specified there. If any of the terms used in this documentation
|
||||
* are unclear please check the specification in the linked section.
|
||||
* (Structure, <a href="id3v2-structure.html#3.2">3.2</a>)
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT ExtendedHeader
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* Constructs an empty ID3v2 extended header.
|
||||
*/
|
||||
ExtendedHeader();
|
||||
|
||||
/*!
|
||||
* Destroys the extended header.
|
||||
*/
|
||||
virtual ~ExtendedHeader();
|
||||
|
||||
/*!
|
||||
* Returns the size of the extended header. This is variable for the
|
||||
* extended header.
|
||||
*/
|
||||
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);
|
||||
|
||||
protected:
|
||||
/*!
|
||||
* Called by setData() to parse the extended header data. It makes this
|
||||
* information available through the public API.
|
||||
*/
|
||||
void parse(const ByteVector &data);
|
||||
|
||||
private:
|
||||
ExtendedHeader(const ExtendedHeader &);
|
||||
ExtendedHeader &operator=(const ExtendedHeader &);
|
||||
|
||||
class ExtendedHeaderPrivate;
|
||||
ExtendedHeaderPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
57
3rdparty/taglib/mpeg/id3v2/id3v2footer.cpp
vendored
Normal file
57
3rdparty/taglib/mpeg/id3v2/id3v2footer.cpp
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include "id3v2footer.h"
|
||||
#include "id3v2header.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class Footer::FooterPrivate
|
||||
{
|
||||
};
|
||||
|
||||
Footer::Footer() :
|
||||
d(0)
|
||||
{
|
||||
}
|
||||
|
||||
Footer::~Footer()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned int Footer::size()
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
|
||||
ByteVector Footer::render(const Header *header) const
|
||||
{
|
||||
ByteVector headerData = header->render();
|
||||
headerData[0] = '3';
|
||||
headerData[1] = 'D';
|
||||
headerData[2] = 'I';
|
||||
return headerData;
|
||||
}
|
||||
82
3rdparty/taglib/mpeg/id3v2/id3v2footer.h
vendored
Normal file
82
3rdparty/taglib/mpeg/id3v2/id3v2footer.h
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_ID3V2FOOTER_H
|
||||
#define TAGLIB_ID3V2FOOTER_H
|
||||
|
||||
#include "taglib_export.h"
|
||||
#include "tbytevector.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
class Header;
|
||||
|
||||
//! 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.
|
||||
*
|
||||
* In fact, at this point, TagLib does not even parse the footer since
|
||||
* it is not useful internally. However, if the flag to include a footer
|
||||
* has been set in the ID3v2::Tag, TagLib will render a footer.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT Footer
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* Constructs an empty ID3v2 footer.
|
||||
*/
|
||||
Footer();
|
||||
/*!
|
||||
* Destroys the footer.
|
||||
*/
|
||||
virtual ~Footer();
|
||||
|
||||
/*!
|
||||
* Returns the size of the footer. Presently this is always 10 bytes.
|
||||
*/
|
||||
static unsigned int size();
|
||||
|
||||
/*!
|
||||
* Renders the footer based on the data in \a header.
|
||||
*/
|
||||
ByteVector render(const Header *header) const;
|
||||
|
||||
private:
|
||||
Footer(const Footer &);
|
||||
Footer &operator=(const Footer &);
|
||||
|
||||
class FooterPrivate;
|
||||
FooterPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
825
3rdparty/taglib/mpeg/id3v2/id3v2frame.cpp
vendored
Normal file
825
3rdparty/taglib/mpeg/id3v2/id3v2frame.cpp
vendored
Normal file
@@ -0,0 +1,825 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <bitset>
|
||||
|
||||
#include <tdebug.h>
|
||||
#include <tstringlist.h>
|
||||
#include <tzlib.h>
|
||||
|
||||
#include "id3v2tag.h"
|
||||
#include "id3v2frame.h"
|
||||
#include "id3v2synchdata.h"
|
||||
|
||||
#include "tpropertymap.h"
|
||||
#include "frames/textidentificationframe.h"
|
||||
#include "frames/urllinkframe.h"
|
||||
#include "frames/unsynchronizedlyricsframe.h"
|
||||
#include "frames/commentsframe.h"
|
||||
#include "frames/uniquefileidentifierframe.h"
|
||||
#include "frames/unknownframe.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class Frame::FramePrivate
|
||||
{
|
||||
public:
|
||||
FramePrivate() :
|
||||
header(0)
|
||||
{}
|
||||
|
||||
~FramePrivate()
|
||||
{
|
||||
delete header;
|
||||
}
|
||||
|
||||
Frame::Header *header;
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
bool isValidFrameID(const ByteVector &frameID)
|
||||
{
|
||||
if(frameID.size() != 4)
|
||||
return false;
|
||||
|
||||
for(ByteVector::ConstIterator it = frameID.begin(); it != frameID.end(); it++) {
|
||||
if( (*it < 'A' || *it > 'Z') && (*it < '0' || *it > '9') ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// static methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsigned int Frame::headerSize()
|
||||
{
|
||||
return Header::size();
|
||||
}
|
||||
|
||||
unsigned int Frame::headerSize(unsigned int version)
|
||||
{
|
||||
return Header::size(version);
|
||||
}
|
||||
|
||||
ByteVector Frame::textDelimiter(String::Type t)
|
||||
{
|
||||
if(t == String::UTF16 || t == String::UTF16BE || t == String::UTF16LE)
|
||||
return ByteVector(2, '\0');
|
||||
else
|
||||
return ByteVector(1, '\0');
|
||||
}
|
||||
|
||||
const String Frame::instrumentPrefix("PERFORMER:");
|
||||
const String Frame::commentPrefix("COMMENT:");
|
||||
const String Frame::lyricsPrefix("LYRICS:");
|
||||
const String Frame::urlPrefix("URL:");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Frame *Frame::createTextualFrame(const String &key, const StringList &values) //static
|
||||
{
|
||||
// check if the key is contained in the key<=>frameID mapping
|
||||
ByteVector frameID = keyToFrameID(key);
|
||||
if(!frameID.isEmpty()) {
|
||||
// Apple proprietary WFED (Podcast URL), MVNM (Movement Name), MVIN (Movement Number) are in fact text frames.
|
||||
if(frameID[0] == 'T' || frameID == "WFED" || frameID == "MVNM" || frameID == "MVIN"){ // text frame
|
||||
TextIdentificationFrame *frame = new TextIdentificationFrame(frameID, String::UTF8);
|
||||
frame->setText(values);
|
||||
return frame;
|
||||
} else if((frameID[0] == 'W') && (values.size() == 1)){ // URL frame (not WXXX); support only one value
|
||||
UrlLinkFrame* frame = new UrlLinkFrame(frameID);
|
||||
frame->setUrl(values.front());
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
if(key == "MUSICBRAINZ_TRACKID" && values.size() == 1) {
|
||||
UniqueFileIdentifierFrame *frame = new UniqueFileIdentifierFrame("http://musicbrainz.org", values.front().data(String::UTF8));
|
||||
return frame;
|
||||
}
|
||||
// now we check if it's one of the "special" cases:
|
||||
// -LYRICS: depending on the number of values, use USLT or TXXX (with description=LYRICS)
|
||||
if((key == "LYRICS" || key.startsWith(lyricsPrefix)) && values.size() == 1){
|
||||
UnsynchronizedLyricsFrame *frame = new UnsynchronizedLyricsFrame(String::UTF8);
|
||||
frame->setDescription(key == "LYRICS" ? key : key.substr(lyricsPrefix.size()));
|
||||
frame->setText(values.front());
|
||||
return frame;
|
||||
}
|
||||
// -URL: depending on the number of values, use WXXX or TXXX (with description=URL)
|
||||
if((key == "URL" || key.startsWith(urlPrefix)) && values.size() == 1){
|
||||
UserUrlLinkFrame *frame = new UserUrlLinkFrame(String::UTF8);
|
||||
frame->setDescription(key == "URL" ? key : key.substr(urlPrefix.size()));
|
||||
frame->setUrl(values.front());
|
||||
return frame;
|
||||
}
|
||||
// -COMMENT: depending on the number of values, use COMM or TXXX (with description=COMMENT)
|
||||
if((key == "COMMENT" || key.startsWith(commentPrefix)) && values.size() == 1){
|
||||
CommentsFrame *frame = new CommentsFrame(String::UTF8);
|
||||
if (key != "COMMENT"){
|
||||
frame->setDescription(key.substr(commentPrefix.size()));
|
||||
}
|
||||
frame->setText(values.front());
|
||||
return frame;
|
||||
}
|
||||
// if non of the above cases apply, we use a TXXX frame with the key as description
|
||||
return new UserTextIdentificationFrame(keyToTXXX(key), values, String::UTF8);
|
||||
}
|
||||
|
||||
Frame::~Frame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
ByteVector Frame::frameID() const
|
||||
{
|
||||
if(d->header)
|
||||
return d->header->frameID();
|
||||
else
|
||||
return ByteVector();
|
||||
}
|
||||
|
||||
unsigned int Frame::size() const
|
||||
{
|
||||
if(d->header)
|
||||
return d->header->frameSize();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Frame::setData(const ByteVector &data)
|
||||
{
|
||||
parse(data);
|
||||
}
|
||||
|
||||
void Frame::setText(const String &)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ByteVector Frame::render() const
|
||||
{
|
||||
ByteVector fieldData = renderFields();
|
||||
d->header->setFrameSize(fieldData.size());
|
||||
ByteVector headerData = d->header->render();
|
||||
|
||||
return headerData + fieldData;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Frame::Frame(const ByteVector &data) :
|
||||
d(new FramePrivate())
|
||||
{
|
||||
d->header = new Header(data);
|
||||
}
|
||||
|
||||
Frame::Frame(Header *h) :
|
||||
d(new FramePrivate())
|
||||
{
|
||||
d->header = h;
|
||||
}
|
||||
|
||||
Frame::Header *Frame::header() const
|
||||
{
|
||||
return d->header;
|
||||
}
|
||||
|
||||
void Frame::setHeader(Header *h, bool deleteCurrent)
|
||||
{
|
||||
if(deleteCurrent)
|
||||
delete d->header;
|
||||
|
||||
d->header = h;
|
||||
}
|
||||
|
||||
void Frame::parse(const ByteVector &data)
|
||||
{
|
||||
if(d->header)
|
||||
d->header->setData(data);
|
||||
else
|
||||
d->header = new Header(data);
|
||||
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
|
||||
ByteVector Frame::fieldData(const ByteVector &frameData) const
|
||||
{
|
||||
unsigned int headerSize = Header::size(d->header->version());
|
||||
|
||||
unsigned int frameDataOffset = headerSize;
|
||||
unsigned int frameDataLength = size();
|
||||
|
||||
if(d->header->compression() || d->header->dataLengthIndicator()) {
|
||||
frameDataLength = SynchData::toUInt(frameData.mid(headerSize, 4));
|
||||
frameDataOffset += 4;
|
||||
}
|
||||
|
||||
if(zlib::isAvailable() && d->header->compression() && !d->header->encryption()) {
|
||||
if(frameData.size() <= frameDataOffset) {
|
||||
debug("Compressed frame doesn't have enough data to decode");
|
||||
return ByteVector();
|
||||
}
|
||||
|
||||
const ByteVector outData = zlib::decompress(frameData.mid(frameDataOffset));
|
||||
if(!outData.isEmpty() && frameDataLength != outData.size()) {
|
||||
debug("frameDataLength does not match the data length returned by zlib");
|
||||
}
|
||||
|
||||
return outData;
|
||||
}
|
||||
|
||||
return frameData.mid(frameDataOffset, frameDataLength);
|
||||
}
|
||||
|
||||
String Frame::readStringField(const ByteVector &data, String::Type encoding, int *position)
|
||||
{
|
||||
int start = 0;
|
||||
|
||||
if(!position)
|
||||
position = &start;
|
||||
|
||||
ByteVector delimiter = textDelimiter(encoding);
|
||||
|
||||
int end = data.find(delimiter, *position, delimiter.size());
|
||||
|
||||
if(end < *position)
|
||||
return String();
|
||||
|
||||
String str;
|
||||
if(encoding == String::Latin1)
|
||||
str = Tag::latin1StringHandler()->parse(data.mid(*position, end - *position));
|
||||
else
|
||||
str = String(data.mid(*position, end - *position), encoding);
|
||||
|
||||
*position = end + delimiter.size();
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
String::Type Frame::checkEncoding(const StringList &fields, String::Type encoding) // static
|
||||
{
|
||||
return checkEncoding(fields, encoding, 4);
|
||||
}
|
||||
|
||||
String::Type Frame::checkEncoding(const StringList &fields, String::Type encoding, unsigned int version) // static
|
||||
{
|
||||
if((encoding == String::UTF8 || encoding == String::UTF16BE) && version != 4)
|
||||
return String::UTF16;
|
||||
|
||||
if(encoding != String::Latin1)
|
||||
return encoding;
|
||||
|
||||
for(StringList::ConstIterator it = fields.begin(); it != fields.end(); ++it) {
|
||||
if(!(*it).isLatin1()) {
|
||||
if(version == 4) {
|
||||
debug("Frame::checkEncoding() -- Rendering using UTF8.");
|
||||
return String::UTF8;
|
||||
}
|
||||
else {
|
||||
debug("Frame::checkEncoding() -- Rendering using UTF16.");
|
||||
return String::UTF16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return String::Latin1;
|
||||
}
|
||||
|
||||
String::Type Frame::checkTextEncoding(const StringList &fields, String::Type encoding) const
|
||||
{
|
||||
return checkEncoding(fields, encoding, header()->version());
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
const char *frameTranslation[][2] = {
|
||||
// Text information frames
|
||||
{ "TALB", "ALBUM"},
|
||||
{ "TBPM", "BPM" },
|
||||
{ "TCOM", "COMPOSER" },
|
||||
{ "TCON", "GENRE" },
|
||||
{ "TCOP", "COPYRIGHT" },
|
||||
{ "TDEN", "ENCODINGTIME" },
|
||||
{ "TDLY", "PLAYLISTDELAY" },
|
||||
{ "TDOR", "ORIGINALDATE" },
|
||||
{ "TDRC", "DATE" },
|
||||
// { "TRDA", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4
|
||||
// { "TDAT", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4
|
||||
// { "TYER", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4
|
||||
// { "TIME", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4
|
||||
{ "TDRL", "RELEASEDATE" },
|
||||
{ "TDTG", "TAGGINGDATE" },
|
||||
{ "TENC", "ENCODEDBY" },
|
||||
{ "TEXT", "LYRICIST" },
|
||||
{ "TFLT", "FILETYPE" },
|
||||
//{ "TIPL", "INVOLVEDPEOPLE" }, handled separately
|
||||
{ "TIT1", "CONTENTGROUP" },
|
||||
{ "TIT2", "TITLE"},
|
||||
{ "TIT3", "SUBTITLE" },
|
||||
{ "TKEY", "INITIALKEY" },
|
||||
{ "TLAN", "LANGUAGE" },
|
||||
{ "TLEN", "LENGTH" },
|
||||
//{ "TMCL", "MUSICIANCREDITS" }, handled separately
|
||||
{ "TMED", "MEDIA" },
|
||||
{ "TMOO", "MOOD" },
|
||||
{ "TOAL", "ORIGINALALBUM" },
|
||||
{ "TOFN", "ORIGINALFILENAME" },
|
||||
{ "TOLY", "ORIGINALLYRICIST" },
|
||||
{ "TOPE", "ORIGINALARTIST" },
|
||||
{ "TOWN", "OWNER" },
|
||||
{ "TPE1", "ARTIST"},
|
||||
{ "TPE2", "ALBUMARTIST" }, // id3's spec says 'PERFORMER', but most programs use 'ALBUMARTIST'
|
||||
{ "TPE3", "CONDUCTOR" },
|
||||
{ "TPE4", "REMIXER" }, // could also be ARRANGER
|
||||
{ "TPOS", "DISCNUMBER" },
|
||||
{ "TPRO", "PRODUCEDNOTICE" },
|
||||
{ "TPUB", "LABEL" },
|
||||
{ "TRCK", "TRACKNUMBER" },
|
||||
{ "TRSN", "RADIOSTATION" },
|
||||
{ "TRSO", "RADIOSTATIONOWNER" },
|
||||
{ "TSOA", "ALBUMSORT" },
|
||||
{ "TSOP", "ARTISTSORT" },
|
||||
{ "TSOT", "TITLESORT" },
|
||||
{ "TSO2", "ALBUMARTISTSORT" }, // non-standard, used by iTunes
|
||||
{ "TSRC", "ISRC" },
|
||||
{ "TSSE", "ENCODING" },
|
||||
// URL frames
|
||||
{ "WCOP", "COPYRIGHTURL" },
|
||||
{ "WOAF", "FILEWEBPAGE" },
|
||||
{ "WOAR", "ARTISTWEBPAGE" },
|
||||
{ "WOAS", "AUDIOSOURCEWEBPAGE" },
|
||||
{ "WORS", "RADIOSTATIONWEBPAGE" },
|
||||
{ "WPAY", "PAYMENTWEBPAGE" },
|
||||
{ "WPUB", "PUBLISHERWEBPAGE" },
|
||||
//{ "WXXX", "URL"}, handled specially
|
||||
// Other frames
|
||||
{ "COMM", "COMMENT" },
|
||||
//{ "USLT", "LYRICS" }, handled specially
|
||||
// Apple iTunes proprietary frames
|
||||
{ "PCST", "PODCAST" },
|
||||
{ "TCAT", "PODCASTCATEGORY" },
|
||||
{ "TDES", "PODCASTDESC" },
|
||||
{ "TGID", "PODCASTID" },
|
||||
{ "WFED", "PODCASTURL" },
|
||||
{ "MVNM", "MOVEMENTNAME" },
|
||||
{ "MVIN", "MOVEMENTNUMBER" },
|
||||
};
|
||||
const size_t frameTranslationSize = sizeof(frameTranslation) / sizeof(frameTranslation[0]);
|
||||
|
||||
const char *txxxFrameTranslation[][2] = {
|
||||
{ "MUSICBRAINZ ALBUM ID", "MUSICBRAINZ_ALBUMID" },
|
||||
{ "MUSICBRAINZ ARTIST ID", "MUSICBRAINZ_ARTISTID" },
|
||||
{ "MUSICBRAINZ ALBUM ARTIST ID", "MUSICBRAINZ_ALBUMARTISTID" },
|
||||
{ "MUSICBRAINZ RELEASE GROUP ID", "MUSICBRAINZ_RELEASEGROUPID" },
|
||||
{ "MUSICBRAINZ WORK ID", "MUSICBRAINZ_WORKID" },
|
||||
{ "ACOUSTID ID", "ACOUSTID_ID" },
|
||||
{ "ACOUSTID FINGERPRINT", "ACOUSTID_FINGERPRINT" },
|
||||
{ "MUSICIP PUID", "MUSICIP_PUID" },
|
||||
};
|
||||
const size_t txxxFrameTranslationSize = sizeof(txxxFrameTranslation) / sizeof(txxxFrameTranslation[0]);
|
||||
|
||||
// list of deprecated frames and their successors
|
||||
const char *deprecatedFrames[][2] = {
|
||||
{"TRDA", "TDRC"}, // 2.3 -> 2.4 (http://en.wikipedia.org/wiki/ID3)
|
||||
{"TDAT", "TDRC"}, // 2.3 -> 2.4
|
||||
{"TYER", "TDRC"}, // 2.3 -> 2.4
|
||||
{"TIME", "TDRC"}, // 2.3 -> 2.4
|
||||
};
|
||||
const size_t deprecatedFramesSize = sizeof(deprecatedFrames) / sizeof(deprecatedFrames[0]);;
|
||||
}
|
||||
|
||||
String Frame::frameIDToKey(const ByteVector &id)
|
||||
{
|
||||
ByteVector id24 = id;
|
||||
for(size_t i = 0; i < deprecatedFramesSize; ++i) {
|
||||
if(id24 == deprecatedFrames[i][0]) {
|
||||
id24 = deprecatedFrames[i][1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
for(size_t i = 0; i < frameTranslationSize; ++i) {
|
||||
if(id24 == frameTranslation[i][0])
|
||||
return frameTranslation[i][1];
|
||||
}
|
||||
return String();
|
||||
}
|
||||
|
||||
ByteVector Frame::keyToFrameID(const String &s)
|
||||
{
|
||||
const String key = s.upper();
|
||||
for(size_t i = 0; i < frameTranslationSize; ++i) {
|
||||
if(key == frameTranslation[i][1])
|
||||
return frameTranslation[i][0];
|
||||
}
|
||||
return ByteVector();
|
||||
}
|
||||
|
||||
String Frame::txxxToKey(const String &description)
|
||||
{
|
||||
const String d = description.upper();
|
||||
for(size_t i = 0; i < txxxFrameTranslationSize; ++i) {
|
||||
if(d == txxxFrameTranslation[i][0])
|
||||
return txxxFrameTranslation[i][1];
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
String Frame::keyToTXXX(const String &s)
|
||||
{
|
||||
const String key = s.upper();
|
||||
for(size_t i = 0; i < txxxFrameTranslationSize; ++i) {
|
||||
if(key == txxxFrameTranslation[i][1])
|
||||
return txxxFrameTranslation[i][0];
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
PropertyMap Frame::asProperties() const
|
||||
{
|
||||
if(dynamic_cast< const UnknownFrame *>(this)) {
|
||||
PropertyMap m;
|
||||
m.unsupportedData().append("UNKNOWN/" + frameID());
|
||||
return m;
|
||||
}
|
||||
const ByteVector &id = frameID();
|
||||
// workaround until this function is virtual
|
||||
if(id == "TXXX")
|
||||
return dynamic_cast< const UserTextIdentificationFrame* >(this)->asProperties();
|
||||
// Apple proprietary WFED (Podcast URL), MVNM (Movement Name), MVIN (Movement Number) are in fact text frames.
|
||||
else if(id[0] == 'T' || id == "WFED" || id == "MVNM" || id == "MVIN")
|
||||
return dynamic_cast< const TextIdentificationFrame* >(this)->asProperties();
|
||||
else if(id == "WXXX")
|
||||
return dynamic_cast< const UserUrlLinkFrame* >(this)->asProperties();
|
||||
else if(id[0] == 'W')
|
||||
return dynamic_cast< const UrlLinkFrame* >(this)->asProperties();
|
||||
else if(id == "COMM")
|
||||
return dynamic_cast< const CommentsFrame* >(this)->asProperties();
|
||||
else if(id == "USLT")
|
||||
return dynamic_cast< const UnsynchronizedLyricsFrame* >(this)->asProperties();
|
||||
else if(id == "UFID")
|
||||
return dynamic_cast< const UniqueFileIdentifierFrame* >(this)->asProperties();
|
||||
PropertyMap m;
|
||||
m.unsupportedData().append(id);
|
||||
return m;
|
||||
}
|
||||
|
||||
void Frame::splitProperties(const PropertyMap &original, PropertyMap &singleFrameProperties,
|
||||
PropertyMap &tiplProperties, PropertyMap &tmclProperties)
|
||||
{
|
||||
singleFrameProperties.clear();
|
||||
tiplProperties.clear();
|
||||
tmclProperties.clear();
|
||||
for(PropertyMap::ConstIterator it = original.begin(); it != original.end(); ++it) {
|
||||
if(TextIdentificationFrame::involvedPeopleMap().contains(it->first))
|
||||
tiplProperties.insert(it->first, it->second);
|
||||
else if(it->first.startsWith(TextIdentificationFrame::instrumentPrefix))
|
||||
tmclProperties.insert(it->first, it->second);
|
||||
else
|
||||
singleFrameProperties.insert(it->first, it->second);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Frame::Header class
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class Frame::Header::HeaderPrivate
|
||||
{
|
||||
public:
|
||||
HeaderPrivate() :
|
||||
frameSize(0),
|
||||
version(4),
|
||||
tagAlterPreservation(false),
|
||||
fileAlterPreservation(false),
|
||||
readOnly(false),
|
||||
groupingIdentity(false),
|
||||
compression(false),
|
||||
encryption(false),
|
||||
unsynchronisation(false),
|
||||
dataLengthIndicator(false)
|
||||
{}
|
||||
|
||||
ByteVector frameID;
|
||||
unsigned int frameSize;
|
||||
unsigned int version;
|
||||
|
||||
// flags
|
||||
|
||||
bool tagAlterPreservation;
|
||||
bool fileAlterPreservation;
|
||||
bool readOnly;
|
||||
bool groupingIdentity;
|
||||
bool compression;
|
||||
bool encryption;
|
||||
bool unsynchronisation;
|
||||
bool dataLengthIndicator;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// static members (Frame::Header)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsigned int Frame::Header::size()
|
||||
{
|
||||
return size(4);
|
||||
}
|
||||
|
||||
unsigned int Frame::Header::size(unsigned int version)
|
||||
{
|
||||
switch(version) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
return 6;
|
||||
case 3:
|
||||
case 4:
|
||||
default:
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members (Frame::Header)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Frame::Header::Header(const ByteVector &data, bool synchSafeInts) :
|
||||
d(new HeaderPrivate())
|
||||
{
|
||||
setData(data, synchSafeInts);
|
||||
}
|
||||
|
||||
Frame::Header::Header(const ByteVector &data, unsigned int version) :
|
||||
d(new HeaderPrivate())
|
||||
{
|
||||
setData(data, version);
|
||||
}
|
||||
|
||||
Frame::Header::~Header()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void Frame::Header::setData(const ByteVector &data, bool synchSafeInts)
|
||||
{
|
||||
setData(data, static_cast<unsigned int>(synchSafeInts ? 4 : 3));
|
||||
}
|
||||
|
||||
void Frame::Header::setData(const ByteVector &data, unsigned int version)
|
||||
{
|
||||
d->version = version;
|
||||
|
||||
switch(version) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
{
|
||||
// ID3v2.2
|
||||
|
||||
if(data.size() < 3) {
|
||||
debug("You must at least specify a frame ID.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the frame ID -- the first three bytes
|
||||
|
||||
d->frameID = data.mid(0, 3);
|
||||
|
||||
// If the full header information was not passed in, do not continue to the
|
||||
// steps to parse the frame size and flags.
|
||||
|
||||
if(data.size() < 6) {
|
||||
d->frameSize = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
d->frameSize = data.toUInt(3, 3, true);
|
||||
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
// ID3v2.3
|
||||
|
||||
if(data.size() < 4) {
|
||||
debug("You must at least specify a frame ID.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the frame ID -- the first four bytes
|
||||
|
||||
d->frameID = data.mid(0, 4);
|
||||
|
||||
// If the full header information was not passed in, do not continue to the
|
||||
// steps to parse the frame size and flags.
|
||||
|
||||
if(data.size() < 10) {
|
||||
d->frameSize = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the size -- the frame size is the four bytes starting at byte four in
|
||||
// the frame header (structure 4)
|
||||
|
||||
d->frameSize = data.toUInt(4U);
|
||||
|
||||
{ // read the first byte of flags
|
||||
std::bitset<8> flags(data[8]);
|
||||
d->tagAlterPreservation = flags[7]; // (structure 3.3.1.a)
|
||||
d->fileAlterPreservation = flags[6]; // (structure 3.3.1.b)
|
||||
d->readOnly = flags[5]; // (structure 3.3.1.c)
|
||||
}
|
||||
|
||||
{ // read the second byte of flags
|
||||
std::bitset<8> flags(data[9]);
|
||||
d->compression = flags[7]; // (structure 3.3.1.i)
|
||||
d->encryption = flags[6]; // (structure 3.3.1.j)
|
||||
d->groupingIdentity = flags[5]; // (structure 3.3.1.k)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
default:
|
||||
{
|
||||
// ID3v2.4
|
||||
|
||||
if(data.size() < 4) {
|
||||
debug("You must at least specify a frame ID.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the frame ID -- the first four bytes
|
||||
|
||||
d->frameID = data.mid(0, 4);
|
||||
|
||||
// If the full header information was not passed in, do not continue to the
|
||||
// steps to parse the frame size and flags.
|
||||
|
||||
if(data.size() < 10) {
|
||||
d->frameSize = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the size -- the frame size is the four bytes starting at byte four in
|
||||
// the frame header (structure 4)
|
||||
|
||||
d->frameSize = SynchData::toUInt(data.mid(4, 4));
|
||||
#ifndef NO_ITUNES_HACKS
|
||||
// iTunes writes v2.4 tags with v2.3-like frame sizes
|
||||
if(d->frameSize > 127) {
|
||||
if(!isValidFrameID(data.mid(d->frameSize + 10, 4))) {
|
||||
unsigned int uintSize = data.toUInt(4U);
|
||||
if(isValidFrameID(data.mid(uintSize + 10, 4))) {
|
||||
d->frameSize = uintSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
{ // read the first byte of flags
|
||||
std::bitset<8> flags(data[8]);
|
||||
d->tagAlterPreservation = flags[6]; // (structure 4.1.1.a)
|
||||
d->fileAlterPreservation = flags[5]; // (structure 4.1.1.b)
|
||||
d->readOnly = flags[4]; // (structure 4.1.1.c)
|
||||
}
|
||||
|
||||
{ // read the second byte of flags
|
||||
std::bitset<8> flags(data[9]);
|
||||
d->groupingIdentity = flags[6]; // (structure 4.1.2.h)
|
||||
d->compression = flags[3]; // (structure 4.1.2.k)
|
||||
d->encryption = flags[2]; // (structure 4.1.2.m)
|
||||
d->unsynchronisation = flags[1]; // (structure 4.1.2.n)
|
||||
d->dataLengthIndicator = flags[0]; // (structure 4.1.2.p)
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector Frame::Header::frameID() const
|
||||
{
|
||||
return d->frameID;
|
||||
}
|
||||
|
||||
void Frame::Header::setFrameID(const ByteVector &id)
|
||||
{
|
||||
d->frameID = id.mid(0, 4);
|
||||
}
|
||||
|
||||
unsigned int Frame::Header::frameSize() const
|
||||
{
|
||||
return d->frameSize;
|
||||
}
|
||||
|
||||
void Frame::Header::setFrameSize(unsigned int size)
|
||||
{
|
||||
d->frameSize = size;
|
||||
}
|
||||
|
||||
unsigned int Frame::Header::version() const
|
||||
{
|
||||
return d->version;
|
||||
}
|
||||
|
||||
void Frame::Header::setVersion(unsigned int version)
|
||||
{
|
||||
d->version = version;
|
||||
}
|
||||
|
||||
bool Frame::Header::tagAlterPreservation() const
|
||||
{
|
||||
return d->tagAlterPreservation;
|
||||
}
|
||||
|
||||
void Frame::Header::setTagAlterPreservation(bool preserve)
|
||||
{
|
||||
d->tagAlterPreservation = preserve;
|
||||
}
|
||||
|
||||
bool Frame::Header::fileAlterPreservation() const
|
||||
{
|
||||
return d->fileAlterPreservation;
|
||||
}
|
||||
|
||||
bool Frame::Header::readOnly() const
|
||||
{
|
||||
return d->readOnly;
|
||||
}
|
||||
|
||||
bool Frame::Header::groupingIdentity() const
|
||||
{
|
||||
return d->groupingIdentity;
|
||||
}
|
||||
|
||||
bool Frame::Header::compression() const
|
||||
{
|
||||
return d->compression;
|
||||
}
|
||||
|
||||
bool Frame::Header::encryption() const
|
||||
{
|
||||
return d->encryption;
|
||||
}
|
||||
|
||||
bool Frame::Header::unsycronisation() const
|
||||
{
|
||||
return unsynchronisation();
|
||||
}
|
||||
|
||||
bool Frame::Header::unsynchronisation() const
|
||||
{
|
||||
return d->unsynchronisation;
|
||||
}
|
||||
|
||||
bool Frame::Header::dataLengthIndicator() const
|
||||
{
|
||||
return d->dataLengthIndicator;
|
||||
}
|
||||
|
||||
ByteVector Frame::Header::render() const
|
||||
{
|
||||
ByteVector flags(2, char(0)); // just blank for the moment
|
||||
|
||||
ByteVector v = d->frameID +
|
||||
(d->version == 3
|
||||
? ByteVector::fromUInt(d->frameSize)
|
||||
: SynchData::fromUInt(d->frameSize)) +
|
||||
flags;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
bool Frame::Header::frameAlterPreservation() const
|
||||
{
|
||||
return fileAlterPreservation();
|
||||
}
|
||||
518
3rdparty/taglib/mpeg/id3v2/id3v2frame.h
vendored
Normal file
518
3rdparty/taglib/mpeg/id3v2/id3v2frame.h
vendored
Normal file
@@ -0,0 +1,518 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_ID3V2FRAME_H
|
||||
#define TAGLIB_ID3V2FRAME_H
|
||||
|
||||
#include "tstring.h"
|
||||
#include "tbytevector.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
class StringList;
|
||||
class PropertyMap;
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
class Tag;
|
||||
class FrameFactory;
|
||||
|
||||
//! 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>)
|
||||
* (<a href="id3v2-frames.html">Frames</a>). This class provides an API for
|
||||
* gathering information about and modifying ID3v2 frames. Funtionallity
|
||||
* specific to a given frame type is handed in one of the many subclasses.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT Frame
|
||||
{
|
||||
friend class Tag;
|
||||
friend class FrameFactory;
|
||||
|
||||
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);
|
||||
|
||||
/*!
|
||||
* Destroys this Frame instance.
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Returns the size of the frame.
|
||||
*/
|
||||
unsigned int size() const;
|
||||
|
||||
/*!
|
||||
* Returns the size of the frame header
|
||||
*
|
||||
* \deprecated This is only accurate for ID3v2.3 or ID3v2.4. Please use
|
||||
* the call below which accepts an ID3v2 version number. In the next
|
||||
* non-binary compatible release this will be made into a non-static
|
||||
* member that checks the internal ID3v2 version.
|
||||
*/
|
||||
static unsigned int headerSize(); // BIC: remove and make non-static
|
||||
|
||||
/*!
|
||||
* Returns the size of the frame header for the given ID3v2 version.
|
||||
*
|
||||
* \deprecated Please see the explanation above.
|
||||
*/
|
||||
static unsigned int headerSize(unsigned int version); // BIC: remove and make non-static
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* 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.
|
||||
*
|
||||
* \note If the frame type supports multiple text encodings, this will not
|
||||
* change the text encoding of the frame; the string will be converted to
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* 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;
|
||||
|
||||
/*!
|
||||
* Render the frame back to its binary format in a ByteVector.
|
||||
*/
|
||||
ByteVector render() const;
|
||||
|
||||
/*!
|
||||
* Returns the text delimiter that is used between fields for the string
|
||||
* type \a 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;
|
||||
/*!
|
||||
* 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;
|
||||
/*!
|
||||
* 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;
|
||||
/*!
|
||||
* 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;
|
||||
|
||||
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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the frame header.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* Called by setData() to parse the frame data. It makes this information
|
||||
* available through the public API.
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Render the field data back to a binary format in a ByteVector. This
|
||||
* must be overridden by subclasses.
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* 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 *positon = 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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* 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;
|
||||
|
||||
|
||||
/*!
|
||||
* Parses the contents of this frame as PropertyMap. If that fails, the returend
|
||||
* 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;
|
||||
|
||||
/*!
|
||||
* 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 &);
|
||||
|
||||
/*!
|
||||
* 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 &);
|
||||
|
||||
/*!
|
||||
* Returns an appropriate TXXX frame description for the given free-form tag key.
|
||||
*/
|
||||
static String keyToTXXX(const String &);
|
||||
|
||||
/*!
|
||||
* Returns a free-form tag name for the given ID3 frame description.
|
||||
*/
|
||||
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
|
||||
* exactly one ID3 frame per key. In the current implementation
|
||||
* this is everything except for the fixed "involved people" keys and keys of the
|
||||
* form "TextIdentificationFrame::instrumentPrefix" + "instrument", which are
|
||||
* mapped to a TMCL frame.
|
||||
* - \a tiplProperties will consist of those keys that are present in
|
||||
* TextIdentificationFrame::involvedPeopleMap()
|
||||
* - \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);
|
||||
|
||||
private:
|
||||
Frame(const Frame &);
|
||||
Frame &operator=(const Frame &);
|
||||
|
||||
class FramePrivate;
|
||||
friend class FramePrivate;
|
||||
FramePrivate *d;
|
||||
};
|
||||
|
||||
//! 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
|
||||
* properties of the frame and also makes it possible to identify the frame
|
||||
* type.
|
||||
*
|
||||
* As such when reading an ID3v2 tag ID3v2::FrameFactory first creates the
|
||||
* frame headers and then creates the appropriate Frame subclass based on
|
||||
* the type and attaches the header.
|
||||
*/
|
||||
|
||||
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.
|
||||
*
|
||||
* \deprecated Please use the constructor below that accepts a version
|
||||
* number.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* Destroys this Header instance.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* 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;
|
||||
|
||||
/*!
|
||||
* Sets the frame's ID to \a id. Only the first four bytes of \a id will
|
||||
* be used.
|
||||
*
|
||||
* \warning This method should in general be avoided. It exists simply to
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* Returns the size of the frame data portion, as set when setData() was
|
||||
* called or set explicitly via setFrameSize().
|
||||
*/
|
||||
unsigned int frameSize() const;
|
||||
|
||||
/*!
|
||||
* Sets the size of the frame data portion.
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Sets the ID3v2 version of the header, changing has impact on the
|
||||
* correct parsing/rendering of frame data.
|
||||
*/
|
||||
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
|
||||
* version. This is only accurate for ID3v2.3 and ID3v2.4. This will be
|
||||
* removed in the next binary incompatible release (2.0) and will be
|
||||
* replaced with a non-static method that checks the frame version.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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
|
||||
* (setting the preservation flag to throw away the frame), but this
|
||||
* follows the ID3v2 standard.
|
||||
*
|
||||
* \see setTagAlterPreservation()
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* The semantics are a little backwards from what would seem natural
|
||||
* (setting the preservation flag to throw away the frame), but this
|
||||
* follows the ID3v2 standard.
|
||||
*
|
||||
* \see tagAlterPreservation()
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Returns true if the frame is meant to be read only.
|
||||
*
|
||||
* \note This flag is currently ignored internally in TagLib.
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Returns true if compression is enabled for this frame.
|
||||
*
|
||||
* \note This flag is currently ignored internally in TagLib.
|
||||
*/
|
||||
bool compression() const;
|
||||
|
||||
/*!
|
||||
* Returns true if encryption is enabled for this frame.
|
||||
*
|
||||
* \note This flag is currently ignored internally in TagLib.
|
||||
*/
|
||||
bool encryption() const;
|
||||
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
bool unsycronisation() const;
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* Returns true if unsynchronisation is enabled for this frame.
|
||||
*/
|
||||
bool unsynchronisation() const;
|
||||
|
||||
/*!
|
||||
* Returns true if the flag for a data length indicator is set.
|
||||
*/
|
||||
bool dataLengthIndicator() const;
|
||||
|
||||
/*!
|
||||
* Render the Header back to binary format in a ByteVector.
|
||||
*/
|
||||
ByteVector render() const;
|
||||
|
||||
/*!
|
||||
* \deprecated
|
||||
*/
|
||||
bool frameAlterPreservation() const;
|
||||
|
||||
private:
|
||||
Header(const Header &);
|
||||
Header &operator=(const Header &);
|
||||
|
||||
class HeaderPrivate;
|
||||
HeaderPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
544
3rdparty/taglib/mpeg/id3v2/id3v2framefactory.cpp
vendored
Normal file
544
3rdparty/taglib/mpeg/id3v2/id3v2framefactory.cpp
vendored
Normal file
@@ -0,0 +1,544 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tdebug.h>
|
||||
#include <tzlib.h>
|
||||
|
||||
#include "id3v2framefactory.h"
|
||||
#include "id3v2synchdata.h"
|
||||
#include "id3v1genres.h"
|
||||
|
||||
#include "frames/attachedpictureframe.h"
|
||||
#include "frames/commentsframe.h"
|
||||
#include "frames/relativevolumeframe.h"
|
||||
#include "frames/textidentificationframe.h"
|
||||
#include "frames/uniquefileidentifierframe.h"
|
||||
#include "frames/unknownframe.h"
|
||||
#include "frames/generalencapsulatedobjectframe.h"
|
||||
#include "frames/urllinkframe.h"
|
||||
#include "frames/unsynchronizedlyricsframe.h"
|
||||
#include "frames/popularimeterframe.h"
|
||||
#include "frames/privateframe.h"
|
||||
#include "frames/ownershipframe.h"
|
||||
#include "frames/synchronizedlyricsframe.h"
|
||||
#include "frames/eventtimingcodesframe.h"
|
||||
#include "frames/chapterframe.h"
|
||||
#include "frames/tableofcontentsframe.h"
|
||||
#include "frames/podcastframe.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
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(")");
|
||||
|
||||
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) {}
|
||||
|
||||
String::Type defaultEncoding;
|
||||
bool useDefaultEncoding;
|
||||
|
||||
template <class T> void setTextEncoding(T *frame)
|
||||
{
|
||||
if(useDefaultEncoding)
|
||||
frame->setTextEncoding(defaultEncoding);
|
||||
}
|
||||
};
|
||||
|
||||
FrameFactory FrameFactory::factory;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FrameFactory *FrameFactory::instance()
|
||||
{
|
||||
return &factory;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
Header tagHeader;
|
||||
tagHeader.setMajorVersion(version);
|
||||
return createFrame(data, &tagHeader);
|
||||
}
|
||||
|
||||
Frame *FrameFactory::createFrame(const ByteVector &origData, Header *tagHeader) const
|
||||
{
|
||||
ByteVector data = origData;
|
||||
unsigned int version = tagHeader->majorVersion();
|
||||
Frame::Header *header = new Frame::Header(data, version);
|
||||
ByteVector frameID = header->frameID();
|
||||
|
||||
// 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())
|
||||
{
|
||||
delete header;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef NO_ITUNES_HACKS
|
||||
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);
|
||||
header->setVersion(2);
|
||||
updateFrame(header);
|
||||
header->setVersion(3);
|
||||
}
|
||||
#endif
|
||||
|
||||
for(ByteVector::ConstIterator it = frameID.begin(); it != frameID.end(); it++) {
|
||||
if( (*it < 'A' || *it > 'Z') && (*it < '0' || *it > '9') ) {
|
||||
delete header;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
frameData = SynchData::decode(frameData);
|
||||
data = data.mid(0, Frame::Header::size(version)) + frameData;
|
||||
}
|
||||
|
||||
// TagLib doesn't mess with encrypted frames, so just treat them
|
||||
// as unknown frames.
|
||||
|
||||
if(!zlib::isAvailable() && header->compression()) {
|
||||
debug("Compressed frames are currently not supported.");
|
||||
return new UnknownFrame(data, header);
|
||||
}
|
||||
|
||||
if(header->encryption()) {
|
||||
debug("Encrypted frames are currently not supported.");
|
||||
return new UnknownFrame(data, header);
|
||||
}
|
||||
|
||||
if(!updateFrame(header)) {
|
||||
header->setTagAlterPreservation(true);
|
||||
return new UnknownFrame(data, header);
|
||||
}
|
||||
|
||||
// updateFrame() might have updated the frame ID.
|
||||
|
||||
frameID = header->frameID();
|
||||
|
||||
// This is where things get necissarily nasty. Here we determine which
|
||||
// Frame subclass (or if none is found simply an Frame) based
|
||||
// on the frame ID. Since there are a lot of possibilities, that means
|
||||
// a lot of if blocks.
|
||||
|
||||
// Text Identification (frames 4.2)
|
||||
|
||||
// Apple proprietary WFED (Podcast URL), MVNM (Movement Name), MVIN (Movement Number) are in fact text frames.
|
||||
if(frameID.startsWith("T") || frameID == "WFED" || frameID == "MVNM" || frameID == "MVIN") {
|
||||
|
||||
TextIdentificationFrame *f = frameID != "TXXX"
|
||||
? new TextIdentificationFrame(data, header)
|
||||
: new UserTextIdentificationFrame(data, header);
|
||||
|
||||
d->setTextEncoding(f);
|
||||
|
||||
if(frameID == "TCON")
|
||||
updateGenre(f);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
// Comments (frames 4.10)
|
||||
|
||||
if(frameID == "COMM") {
|
||||
CommentsFrame *f = new CommentsFrame(data, header);
|
||||
d->setTextEncoding(f);
|
||||
return f;
|
||||
}
|
||||
|
||||
// Attached Picture (frames 4.14)
|
||||
|
||||
if(frameID == "APIC") {
|
||||
AttachedPictureFrame *f = new AttachedPictureFrame(data, header);
|
||||
d->setTextEncoding(f);
|
||||
return f;
|
||||
}
|
||||
|
||||
// ID3v2.2 Attached Picture
|
||||
|
||||
if(frameID == "PIC") {
|
||||
AttachedPictureFrame *f = new AttachedPictureFrameV22(data, header);
|
||||
d->setTextEncoding(f);
|
||||
return f;
|
||||
}
|
||||
|
||||
// Relative Volume Adjustment (frames 4.11)
|
||||
|
||||
if(frameID == "RVA2")
|
||||
return new RelativeVolumeFrame(data, header);
|
||||
|
||||
// Unique File Identifier (frames 4.1)
|
||||
|
||||
if(frameID == "UFID")
|
||||
return new UniqueFileIdentifierFrame(data, header);
|
||||
|
||||
// General Encapsulated Object (frames 4.15)
|
||||
|
||||
if(frameID == "GEOB") {
|
||||
GeneralEncapsulatedObjectFrame *f = new GeneralEncapsulatedObjectFrame(data, header);
|
||||
d->setTextEncoding(f);
|
||||
return f;
|
||||
}
|
||||
|
||||
// URL link (frames 4.3)
|
||||
|
||||
if(frameID.startsWith("W")) {
|
||||
if(frameID != "WXXX") {
|
||||
return new UrlLinkFrame(data, header);
|
||||
}
|
||||
else {
|
||||
UserUrlLinkFrame *f = new UserUrlLinkFrame(data, header);
|
||||
d->setTextEncoding(f);
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
// Unsynchronized lyric/text transcription (frames 4.8)
|
||||
|
||||
if(frameID == "USLT") {
|
||||
UnsynchronizedLyricsFrame *f = new UnsynchronizedLyricsFrame(data, header);
|
||||
if(d->useDefaultEncoding)
|
||||
f->setTextEncoding(d->defaultEncoding);
|
||||
return f;
|
||||
}
|
||||
|
||||
// Synchronised lyrics/text (frames 4.9)
|
||||
|
||||
if(frameID == "SYLT") {
|
||||
SynchronizedLyricsFrame *f = new SynchronizedLyricsFrame(data, header);
|
||||
if(d->useDefaultEncoding)
|
||||
f->setTextEncoding(d->defaultEncoding);
|
||||
return f;
|
||||
}
|
||||
|
||||
// Event timing codes (frames 4.5)
|
||||
|
||||
if(frameID == "ETCO")
|
||||
return new EventTimingCodesFrame(data, header);
|
||||
|
||||
// Popularimeter (frames 4.17)
|
||||
|
||||
if(frameID == "POPM")
|
||||
return new PopularimeterFrame(data, header);
|
||||
|
||||
// Private (frames 4.27)
|
||||
|
||||
if(frameID == "PRIV")
|
||||
return new PrivateFrame(data, header);
|
||||
|
||||
// Ownership (frames 4.22)
|
||||
|
||||
if(frameID == "OWNE") {
|
||||
OwnershipFrame *f = new OwnershipFrame(data, header);
|
||||
d->setTextEncoding(f);
|
||||
return f;
|
||||
}
|
||||
|
||||
// Chapter (ID3v2 chapters 1.0)
|
||||
|
||||
if(frameID == "CHAP")
|
||||
return new ChapterFrame(tagHeader, data, header);
|
||||
|
||||
// Table of contents (ID3v2 chapters 1.0)
|
||||
|
||||
if(frameID == "CTOC")
|
||||
return new TableOfContentsFrame(tagHeader, data, header);
|
||||
|
||||
// Apple proprietary PCST (Podcast)
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
String date(tdat->data().mid(1), String::Type(tdat->data()[0]));
|
||||
if(date.length() == 4) {
|
||||
tdrc->setText(tdrc->toString() + '-' + date.substr(2, 2) + '-' + date.substr(0, 2));
|
||||
if(tag->frameList("TIME").size() == 1) {
|
||||
UnknownFrame *timeframe = static_cast<UnknownFrame *>(tag->frameList("TIME").front());
|
||||
if(timeframe->data().size() >= 5) {
|
||||
String time(timeframe->data().mid(1), String::Type(timeframe->data()[0]));
|
||||
if(time.length() == 4) {
|
||||
tdrc->setText(tdrc->toString() + 'T' + time.substr(0, 2) + ':' + time.substr(2, 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String::Type FrameFactory::defaultTextEncoding() const
|
||||
{
|
||||
return d->defaultEncoding;
|
||||
}
|
||||
|
||||
void FrameFactory::setDefaultTextEncoding(String::Type encoding)
|
||||
{
|
||||
d->useDefaultEncoding = true;
|
||||
d->defaultEncoding = encoding;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FrameFactory::FrameFactory() :
|
||||
d(new FrameFactoryPrivate())
|
||||
{
|
||||
}
|
||||
|
||||
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" },
|
||||
|
||||
// Apple iTunes nonstandard frames
|
||||
{ "PCS", "PCST" },
|
||||
{ "TCT", "TCAT" },
|
||||
{ "TDR", "TDRL" },
|
||||
{ "TDS", "TDES" },
|
||||
{ "TID", "TGID" },
|
||||
{ "WFD", "WFED" },
|
||||
{ "MVN", "MVNM" },
|
||||
{ "MVI", "MVIN" },
|
||||
};
|
||||
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]);
|
||||
}
|
||||
|
||||
bool FrameFactory::updateFrame(Frame::Header *header) const
|
||||
{
|
||||
const ByteVector frameID = header->frameID();
|
||||
|
||||
switch(header->version()) {
|
||||
|
||||
case 2: // ID3v2.2
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
case 3: // ID3v2.3
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
if(frameID == "TRDC")
|
||||
header->setFrameID("TDRC");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
164
3rdparty/taglib/mpeg/id3v2/id3v2framefactory.h
vendored
Normal file
164
3rdparty/taglib/mpeg/id3v2/id3v2framefactory.h
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_ID3V2FRAMEFACTORY_H
|
||||
#define TAGLIB_ID3V2FRAMEFACTORY_H
|
||||
|
||||
#include "taglib_export.h"
|
||||
#include "tbytevector.h"
|
||||
#include "id3v2frame.h"
|
||||
#include "id3v2header.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
class TextIdentificationFrame;
|
||||
|
||||
//! 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.
|
||||
*
|
||||
* Reimplementing this factory is the key to adding support for frame types
|
||||
* not directly supported by TagLib to your application. To do so you would
|
||||
* subclass this factory reimplement createFrame(). Then by setting your
|
||||
* factory to be the default factory in ID3v2::Tag constructor you can
|
||||
* implement behavior that will allow for new ID3v2::Frame subclasses (also
|
||||
* provided by you) to be used.
|
||||
*
|
||||
* This implements both <i>abstract factory</i> and <i>singleton</i> patterns
|
||||
* of which more information is available on the web and in software design
|
||||
* textbooks (Notably <i>Design Patters</i>).
|
||||
*
|
||||
* \note You do not need to use this factory to create new frames to add to
|
||||
* an ID3v2::Tag. You can instantiate frame subclasses directly (with new)
|
||||
* and add them to a tag using ID3v2::Tag::addFrame()
|
||||
*
|
||||
* \see ID3v2::Tag::addFrame()
|
||||
*/
|
||||
|
||||
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.
|
||||
*
|
||||
* \deprecated Please use the method below that accepts a ID3v2::Header
|
||||
* instance in new code.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* \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;
|
||||
|
||||
/*!
|
||||
* Create a frame based on \a data. \a tagHeader should be a valid
|
||||
* ID3v2::Header instance.
|
||||
*/
|
||||
// BIC: make virtual
|
||||
Frame *createFrame(const ByteVector &data, 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;
|
||||
|
||||
/*!
|
||||
* 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
|
||||
* converted to this type (unless it's explicitly set differently for the
|
||||
* individual frame) when being rendered.
|
||||
*
|
||||
* \see setDefaultTextEncoding()
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* Valid string types for ID3v2 tags are Latin1, UTF8, UTF16 and UTF16BE.
|
||||
*
|
||||
* \see defaultTextEncoding()
|
||||
*/
|
||||
void setDefaultTextEncoding(String::Type encoding);
|
||||
|
||||
protected:
|
||||
/*!
|
||||
* Constructs a frame factory. Because this is a singleton this method is
|
||||
* protected, but may be used for subclasses.
|
||||
*/
|
||||
FrameFactory();
|
||||
|
||||
/*!
|
||||
* Destroys the frame factory.
|
||||
*/
|
||||
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
|
||||
* the frame or indicates that it should be discarded.
|
||||
*
|
||||
* This method with return true (with or without changes to the frame) if
|
||||
* this frame should be kept or false if it should be discarded.
|
||||
*
|
||||
* See the id3v2.4.0-changes.txt document for further information.
|
||||
*/
|
||||
virtual bool updateFrame(Frame::Header *header) const;
|
||||
|
||||
private:
|
||||
FrameFactory(const FrameFactory &);
|
||||
FrameFactory &operator=(const FrameFactory &);
|
||||
|
||||
static FrameFactory factory;
|
||||
|
||||
class FrameFactoryPrivate;
|
||||
FrameFactoryPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
239
3rdparty/taglib/mpeg/id3v2/id3v2header.cpp
vendored
Normal file
239
3rdparty/taglib/mpeg/id3v2/id3v2header.cpp
vendored
Normal file
@@ -0,0 +1,239 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include <bitset>
|
||||
|
||||
#include <tstring.h>
|
||||
#include <tdebug.h>
|
||||
|
||||
#include "id3v2header.h"
|
||||
#include "id3v2footer.h"
|
||||
#include "id3v2synchdata.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
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;
|
||||
|
||||
bool unsynchronisation;
|
||||
bool extendedHeader;
|
||||
bool experimentalIndicator;
|
||||
bool footerPresent;
|
||||
|
||||
unsigned int tagSize;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// static members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsigned int Header::size()
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
|
||||
ByteVector Header::fileIdentifier()
|
||||
{
|
||||
return ByteVector::fromCString("ID3");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Header::Header() :
|
||||
d(new HeaderPrivate())
|
||||
{
|
||||
}
|
||||
|
||||
Header::Header(const ByteVector &data) :
|
||||
d(new HeaderPrivate())
|
||||
{
|
||||
parse(data);
|
||||
}
|
||||
|
||||
Header::~Header()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
unsigned int Header::majorVersion() const
|
||||
{
|
||||
return d->majorVersion;
|
||||
}
|
||||
|
||||
void Header::setMajorVersion(unsigned int version)
|
||||
{
|
||||
d->majorVersion = version;
|
||||
}
|
||||
|
||||
unsigned int Header::revisionNumber() const
|
||||
{
|
||||
return d->revisionNumber;
|
||||
}
|
||||
|
||||
bool Header::unsynchronisation() const
|
||||
{
|
||||
return d->unsynchronisation;
|
||||
}
|
||||
|
||||
bool Header::extendedHeader() const
|
||||
{
|
||||
return d->extendedHeader;
|
||||
}
|
||||
|
||||
bool Header::experimentalIndicator() const
|
||||
{
|
||||
return d->experimentalIndicator;
|
||||
}
|
||||
|
||||
bool Header::footerPresent() const
|
||||
{
|
||||
return d->footerPresent;
|
||||
}
|
||||
|
||||
unsigned int Header::tagSize() const
|
||||
{
|
||||
return d->tagSize;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
d->tagSize = s;
|
||||
}
|
||||
|
||||
void Header::setData(const ByteVector &data)
|
||||
{
|
||||
parse(data);
|
||||
}
|
||||
|
||||
ByteVector Header::render() const
|
||||
{
|
||||
ByteVector v;
|
||||
|
||||
// add the file identifier -- "ID3"
|
||||
v.append(fileIdentifier());
|
||||
|
||||
// add the version number -- we always render a 2.4.0 tag regardless of what
|
||||
// the tag originally was.
|
||||
|
||||
v.append(char(majorVersion()));
|
||||
v.append(char(0));
|
||||
|
||||
// Currently we don't actually support writing extended headers, footers or
|
||||
// unsynchronized tags, make sure that the flags are set accordingly.
|
||||
|
||||
d->extendedHeader = false;
|
||||
d->footerPresent = false;
|
||||
d->unsynchronisation = false;
|
||||
|
||||
// render and add the flags
|
||||
std::bitset<8> flags;
|
||||
|
||||
flags[7] = d->unsynchronisation;
|
||||
flags[6] = d->extendedHeader;
|
||||
flags[5] = d->experimentalIndicator;
|
||||
flags[4] = d->footerPresent;
|
||||
|
||||
v.append(char(flags.to_ulong()));
|
||||
|
||||
// add the size
|
||||
v.append(SynchData::fromUInt(d->tagSize));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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
|
||||
// synch-safe integer, so all bytes must be less than 128. If this is not
|
||||
// true then this is an invalid tag.
|
||||
|
||||
// note that we're doing things a little out of order here -- the size is
|
||||
// later in the bytestream than the version
|
||||
|
||||
ByteVector sizeData = data.mid(6, 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) {
|
||||
d->tagSize = 0;
|
||||
debug("TagLib::ID3v2::Header::parse() - One of the size bytes in the id3v2 header was greater than the allowed 128.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 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")
|
||||
|
||||
// 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)
|
||||
|
||||
// Get the size from the remaining four bytes (read above)
|
||||
|
||||
d->tagSize = SynchData::toUInt(sizeData); // (structure 3.1 "size")
|
||||
}
|
||||
175
3rdparty/taglib/mpeg/id3v2/id3v2header.h
vendored
Normal file
175
3rdparty/taglib/mpeg/id3v2/id3v2header.h
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_ID3V2HEADER_H
|
||||
#define TAGLIB_ID3V2HEADER_H
|
||||
|
||||
#include "tbytevector.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! 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
|
||||
* specified there. If any of the terms used in this documentation are
|
||||
* unclear please check the specification in the linked section.
|
||||
* (Structure, <a href="id3v2-structure.html#3.1">3.1</a>)
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT Header
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* Constructs an empty ID3v2 header.
|
||||
*/
|
||||
Header();
|
||||
|
||||
/*!
|
||||
* Constructs an ID3v2 header based on \a data. parse() is called
|
||||
* immediately.
|
||||
*/
|
||||
Header(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Destroys the 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;
|
||||
|
||||
/*!
|
||||
* 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()
|
||||
*
|
||||
* \note This is used by the internal parser; this will not change the
|
||||
* version which is written and in general should not be called by API
|
||||
* users.
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Returns true if unsynchronisation has been applied to all frames.
|
||||
*/
|
||||
bool unsynchronisation() const;
|
||||
|
||||
/*!
|
||||
* Returns true if an extended header is present in the tag.
|
||||
*/
|
||||
bool extendedHeader() const;
|
||||
|
||||
/*!
|
||||
* Returns true if the experimental indicator flag is set.
|
||||
*/
|
||||
bool experimentalIndicator() const;
|
||||
|
||||
/*!
|
||||
* Returns true if a footer is present in the tag.
|
||||
*/
|
||||
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).
|
||||
*
|
||||
* \note This is the value as read from the header to which TagLib attempts
|
||||
* to provide an API to; it was not a design decision on the part of TagLib
|
||||
* to not include the mentioned portions of the tag in the \e size.
|
||||
*
|
||||
* \see completeTagSize()
|
||||
*/
|
||||
unsigned int tagSize() const;
|
||||
|
||||
/*!
|
||||
* Returns the tag size, including the header and, if present, the footer
|
||||
* size.
|
||||
*
|
||||
* \see tagSize()
|
||||
*/
|
||||
unsigned int completeTagSize() const;
|
||||
|
||||
/*!
|
||||
* Set the tag size to \a s.
|
||||
* \see tagSize()
|
||||
*/
|
||||
void setTagSize(unsigned int s);
|
||||
|
||||
/*!
|
||||
* Returns the size of the header. Presently this is always 10 bytes.
|
||||
*/
|
||||
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();
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* Renders the Header back to binary format.
|
||||
*/
|
||||
ByteVector render() const;
|
||||
|
||||
protected:
|
||||
/*!
|
||||
* Called by setData() to parse the header data. It makes this information
|
||||
* available through the public API.
|
||||
*/
|
||||
void parse(const ByteVector &data);
|
||||
|
||||
private:
|
||||
Header(const Header &);
|
||||
Header &operator=(const Header &);
|
||||
|
||||
class HeaderPrivate;
|
||||
HeaderPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
98
3rdparty/taglib/mpeg/id3v2/id3v2synchdata.cpp
vendored
Normal file
98
3rdparty/taglib/mpeg/id3v2/id3v2synchdata.cpp
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "id3v2synchdata.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
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) {
|
||||
notSynchSafe = true;
|
||||
break;
|
||||
}
|
||||
|
||||
sum |= (data[i] & 0x7f) << ((last - i) * 7);
|
||||
}
|
||||
|
||||
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) {
|
||||
sum = data.toUInt(0, true);
|
||||
}
|
||||
else {
|
||||
ByteVector tmp(data);
|
||||
tmp.resize(4);
|
||||
sum = tmp.toUInt(0, true);
|
||||
}
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
ByteVector SynchData::fromUInt(unsigned int value)
|
||||
{
|
||||
ByteVector v(4, 0);
|
||||
|
||||
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)
|
||||
{
|
||||
// We have this optimized method instead of using ByteVector::replace(),
|
||||
// since it makes a great difference when decoding huge unsynchronized frames.
|
||||
|
||||
ByteVector result(data.size());
|
||||
|
||||
ByteVector::ConstIterator src = data.begin();
|
||||
ByteVector::Iterator dst = result.begin();
|
||||
|
||||
while(src < data.end() - 1) {
|
||||
*dst++ = *src++;
|
||||
|
||||
if(*(src - 1) == '\xff' && *src == '\x00')
|
||||
src++;
|
||||
}
|
||||
|
||||
if(src < data.end())
|
||||
*dst++ = *src++;
|
||||
|
||||
result.resize(static_cast<unsigned int>(dst - result.begin()));
|
||||
|
||||
return result;
|
||||
}
|
||||
70
3rdparty/taglib/mpeg/id3v2/id3v2synchdata.h
vendored
Normal file
70
3rdparty/taglib/mpeg/id3v2/id3v2synchdata.h
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_ID3V2SYNCHDATA_H
|
||||
#define TAGLIB_ID3V2SYNCHDATA_H
|
||||
|
||||
#include "tbytevector.h"
|
||||
#include "taglib.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! 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
|
||||
* methods for converting to and from these values to ByteVectors for
|
||||
* things rendering and parsing ID3v2 data.
|
||||
*/
|
||||
|
||||
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);
|
||||
|
||||
/*!
|
||||
* Returns a 4 byte (32 bit) synchsafe integer based on \a 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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
794
3rdparty/taglib/mpeg/id3v2/id3v2tag.cpp
vendored
Normal file
794
3rdparty/taglib/mpeg/id3v2/id3v2tag.cpp
vendored
Normal file
@@ -0,0 +1,794 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <tfile.h>
|
||||
#include <tbytevector.h>
|
||||
#include <tpropertymap.h>
|
||||
#include <tdebug.h>
|
||||
|
||||
#include "id3v2tag.h"
|
||||
#include "id3v2header.h"
|
||||
#include "id3v2extendedheader.h"
|
||||
#include "id3v2footer.h"
|
||||
#include "id3v2synchdata.h"
|
||||
#include "id3v1genres.h"
|
||||
|
||||
#include "frames/textidentificationframe.h"
|
||||
#include "frames/commentsframe.h"
|
||||
#include "frames/urllinkframe.h"
|
||||
#include "frames/uniquefileidentifierframe.h"
|
||||
#include "frames/unsynchronizedlyricsframe.h"
|
||||
#include "frames/unknownframe.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
namespace
|
||||
{
|
||||
const ID3v2::Latin1StringHandler defaultStringHandler;
|
||||
const ID3v2::Latin1StringHandler *stringHandler = &defaultStringHandler;
|
||||
|
||||
const long MinPaddingSize = 1024;
|
||||
const long MaxPaddingSize = 1024 * 1024;
|
||||
}
|
||||
|
||||
class ID3v2::Tag::TagPrivate
|
||||
{
|
||||
public:
|
||||
TagPrivate() :
|
||||
factory(0),
|
||||
file(0),
|
||||
tagOffset(0),
|
||||
extendedHeader(0),
|
||||
footer(0)
|
||||
{
|
||||
frameList.setAutoDelete(true);
|
||||
}
|
||||
|
||||
~TagPrivate()
|
||||
{
|
||||
delete extendedHeader;
|
||||
delete footer;
|
||||
}
|
||||
|
||||
const FrameFactory *factory;
|
||||
|
||||
File *file;
|
||||
long tagOffset;
|
||||
|
||||
Header header;
|
||||
ExtendedHeader *extendedHeader;
|
||||
Footer *footer;
|
||||
|
||||
FrameListMap frameListMap;
|
||||
FrameList frameList;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// StringHandler implementation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Latin1StringHandler::Latin1StringHandler()
|
||||
{
|
||||
}
|
||||
|
||||
Latin1StringHandler::~Latin1StringHandler()
|
||||
{
|
||||
}
|
||||
|
||||
String Latin1StringHandler::parse(const ByteVector &data) const
|
||||
{
|
||||
return String(data, String::Latin1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ID3v2::Tag::Tag() :
|
||||
TagLib::Tag(),
|
||||
d(new TagPrivate())
|
||||
{
|
||||
d->factory = FrameFactory::instance();
|
||||
}
|
||||
|
||||
ID3v2::Tag::Tag(File *file, long tagOffset, const FrameFactory *factory) :
|
||||
TagLib::Tag(),
|
||||
d(new TagPrivate())
|
||||
{
|
||||
d->factory = factory;
|
||||
d->file = file;
|
||||
d->tagOffset = tagOffset;
|
||||
|
||||
read();
|
||||
}
|
||||
|
||||
ID3v2::Tag::~Tag()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
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())
|
||||
return d->frameListMap["TPE1"].front()->toString();
|
||||
return String();
|
||||
}
|
||||
|
||||
String ID3v2::Tag::album() const
|
||||
{
|
||||
if(!d->frameListMap["TALB"].isEmpty())
|
||||
return d->frameListMap["TALB"].front()->toString();
|
||||
return String();
|
||||
}
|
||||
|
||||
String ID3v2::Tag::comment() const
|
||||
{
|
||||
const FrameList &comments = d->frameListMap["COMM"];
|
||||
|
||||
if(comments.isEmpty())
|
||||
return String();
|
||||
|
||||
for(FrameList::ConstIterator it = comments.begin(); it != comments.end(); ++it)
|
||||
{
|
||||
CommentsFrame *frame = dynamic_cast<CommentsFrame *>(*it);
|
||||
|
||||
if(frame && frame->description().isEmpty())
|
||||
return (*it)->toString();
|
||||
}
|
||||
|
||||
return comments.front()->toString();
|
||||
}
|
||||
|
||||
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()))
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
// ID3v2.4 lists genres as the fields in its frames field list. If the field
|
||||
// is simply a number it can be assumed that it is an ID3v1 genre number.
|
||||
// Here was assume that if an ID3v1 string is present that it should be
|
||||
// appended to the genre string. Multiple fields will be appended as the
|
||||
// string is built.
|
||||
|
||||
TextIdentificationFrame *f = static_cast<TextIdentificationFrame *>(
|
||||
d->frameListMap["TCON"].front());
|
||||
|
||||
StringList fields = f->fieldList();
|
||||
|
||||
StringList genres;
|
||||
|
||||
for(StringList::Iterator it = fields.begin(); it != fields.end(); ++it) {
|
||||
|
||||
if((*it).isEmpty())
|
||||
continue;
|
||||
|
||||
bool ok;
|
||||
int number = (*it).toInt(&ok);
|
||||
if(ok && number >= 0 && number <= 255) {
|
||||
*it = ID3v1::genre(number);
|
||||
}
|
||||
|
||||
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())
|
||||
return d->frameListMap["TDRC"].front()->toString().substr(0, 4).toInt();
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
setTextFrame("TIT2", s);
|
||||
}
|
||||
|
||||
void ID3v2::Tag::setArtist(const String &s)
|
||||
{
|
||||
setTextFrame("TPE1", s);
|
||||
}
|
||||
|
||||
void ID3v2::Tag::setAlbum(const String &s)
|
||||
{
|
||||
setTextFrame("TALB", s);
|
||||
}
|
||||
|
||||
void ID3v2::Tag::setComment(const String &s)
|
||||
{
|
||||
if(s.isEmpty()) {
|
||||
removeFrames("COMM");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!d->frameListMap["COMM"].isEmpty())
|
||||
d->frameListMap["COMM"].front()->setText(s);
|
||||
else {
|
||||
CommentsFrame *f = new CommentsFrame(d->factory->defaultTextEncoding());
|
||||
addFrame(f);
|
||||
f->setText(s);
|
||||
}
|
||||
}
|
||||
|
||||
void ID3v2::Tag::setGenre(const String &s)
|
||||
{
|
||||
if(s.isEmpty()) {
|
||||
removeFrames("TCON");
|
||||
return;
|
||||
}
|
||||
|
||||
// iTunes can't handle correctly encoded ID3v2.4 numerical genres. Just use
|
||||
// strings until iTunes sucks less.
|
||||
|
||||
#ifdef NO_ITUNES_HACKS
|
||||
|
||||
int index = ID3v1::genreIndex(s);
|
||||
|
||||
if(index != 255)
|
||||
setTextFrame("TCON", String::number(index));
|
||||
else
|
||||
setTextFrame("TCON", s);
|
||||
|
||||
#else
|
||||
|
||||
setTextFrame("TCON", s);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
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) {
|
||||
removeFrames("TRCK");
|
||||
return;
|
||||
}
|
||||
setTextFrame("TRCK", String::number(i));
|
||||
}
|
||||
|
||||
bool ID3v2::Tag::isEmpty() const
|
||||
{
|
||||
return d->frameList.isEmpty();
|
||||
}
|
||||
|
||||
Header *ID3v2::Tag::header() const
|
||||
{
|
||||
return &(d->header);
|
||||
}
|
||||
|
||||
ExtendedHeader *ID3v2::Tag::extendedHeader() const
|
||||
{
|
||||
return d->extendedHeader;
|
||||
}
|
||||
|
||||
Footer *ID3v2::Tag::footer() const
|
||||
{
|
||||
return d->footer;
|
||||
}
|
||||
|
||||
const FrameListMap &ID3v2::Tag::frameListMap() const
|
||||
{
|
||||
return d->frameListMap;
|
||||
}
|
||||
|
||||
const FrameList &ID3v2::Tag::frameList() const
|
||||
{
|
||||
return d->frameList;
|
||||
}
|
||||
|
||||
const FrameList &ID3v2::Tag::frameList(const ByteVector &frameID) const
|
||||
{
|
||||
return d->frameListMap[frameID];
|
||||
}
|
||||
|
||||
void ID3v2::Tag::addFrame(Frame *frame)
|
||||
{
|
||||
d->frameList.append(frame);
|
||||
d->frameListMap[frame->frameID()].append(frame);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// ...and from the frame list map
|
||||
it = d->frameListMap[frame->frameID()].find(frame);
|
||||
d->frameListMap[frame->frameID()].erase(it);
|
||||
|
||||
// ...and delete as desired
|
||||
if(del)
|
||||
delete frame;
|
||||
}
|
||||
|
||||
void ID3v2::Tag::removeFrames(const ByteVector &id)
|
||||
{
|
||||
FrameList l = d->frameListMap[id];
|
||||
for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
|
||||
removeFrame(*it, true);
|
||||
}
|
||||
|
||||
PropertyMap ID3v2::Tag::properties() const
|
||||
{
|
||||
PropertyMap properties;
|
||||
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/")) {
|
||||
String frameID = it->substr(String("UNKNOWN/").size());
|
||||
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++)
|
||||
if (dynamic_cast<const UnknownFrame *>(*fit) != 0)
|
||||
removeFrame(*fit);
|
||||
}
|
||||
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
|
||||
String description = it->substr(5);
|
||||
Frame *frame = 0;
|
||||
if(id == "TXXX")
|
||||
frame = UserTextIdentificationFrame::find(this, description);
|
||||
else if(id == "WXXX")
|
||||
frame = UserUrlLinkFrame::find(this, description);
|
||||
else if(id == "COMM")
|
||||
frame = CommentsFrame::findByDescription(this, description);
|
||||
else if(id == "USLT")
|
||||
frame = UnsynchronizedLyricsFrame::findByDescription(this, description);
|
||||
else if(id == "UFID")
|
||||
frame = UniqueFileIdentifierFrame::findByOwner(this, description);
|
||||
if(frame)
|
||||
removeFrame(frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
PropertyMap properties;
|
||||
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){
|
||||
PropertyMap frameProperties = (*lit)->asProperties();
|
||||
if(it->first == "TIPL") {
|
||||
if (tiplProperties != frameProperties)
|
||||
framesToDelete.append(*lit);
|
||||
else
|
||||
tiplProperties.erase(frameProperties);
|
||||
} else if(it->first == "TMCL") {
|
||||
if (tmclProperties != frameProperties)
|
||||
framesToDelete.append(*lit);
|
||||
else
|
||||
tmclProperties.erase(frameProperties);
|
||||
} else if(!properties.contains(frameProperties))
|
||||
framesToDelete.append(*lit);
|
||||
else
|
||||
properties.erase(frameProperties);
|
||||
}
|
||||
}
|
||||
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));
|
||||
// proceed with the musician credit list (TMCL)
|
||||
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)
|
||||
addFrame(Frame::createTextualFrame(it->first, it->second));
|
||||
return PropertyMap(); // ID3 implements the complete PropertyMap interface, so an empty map is returned
|
||||
}
|
||||
|
||||
ByteVector ID3v2::Tag::render() const
|
||||
{
|
||||
return render(4);
|
||||
}
|
||||
|
||||
void ID3v2::Tag::downgradeFrames(FrameList *frames, FrameList *newFrames) const
|
||||
{
|
||||
#ifdef NO_ITUNES_HACKS
|
||||
const char *unsupportedFrames[] = {
|
||||
"ASPI", "EQU2", "RVA2", "SEEK", "SIGN", "TDRL", "TDTG",
|
||||
"TMOO", "TPRO", "TSOA", "TSOT", "TSST", "TSOP", 0
|
||||
};
|
||||
#else
|
||||
// iTunes writes and reads TSOA, TSOT, TSOP to ID3v2.3.
|
||||
const char *unsupportedFrames[] = {
|
||||
"ASPI", "EQU2", "RVA2", "SEEK", "SIGN", "TDRL", "TDTG",
|
||||
"TMOO", "TPRO", "TSST", 0
|
||||
};
|
||||
#endif
|
||||
ID3v2::TextIdentificationFrame *frameTDOR = 0;
|
||||
ID3v2::TextIdentificationFrame *frameTDRC = 0;
|
||||
ID3v2::TextIdentificationFrame *frameTIPL = 0;
|
||||
ID3v2::TextIdentificationFrame *frameTMCL = 0;
|
||||
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");
|
||||
frame = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(frame && frameID == "TDOR") {
|
||||
frameTDOR = dynamic_cast<ID3v2::TextIdentificationFrame *>(frame);
|
||||
frame = 0;
|
||||
}
|
||||
if(frame && frameID == "TDRC") {
|
||||
frameTDRC = dynamic_cast<ID3v2::TextIdentificationFrame *>(frame);
|
||||
frame = 0;
|
||||
}
|
||||
if(frame && frameID == "TIPL") {
|
||||
frameTIPL = dynamic_cast<ID3v2::TextIdentificationFrame *>(frame);
|
||||
frame = 0;
|
||||
}
|
||||
if(frame && frameID == "TMCL") {
|
||||
frameTMCL = dynamic_cast<ID3v2::TextIdentificationFrame *>(frame);
|
||||
frame = 0;
|
||||
}
|
||||
if(frame) {
|
||||
frames->append(frame);
|
||||
}
|
||||
}
|
||||
if(frameTDOR) {
|
||||
String content = frameTDOR->toString();
|
||||
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) {
|
||||
String content = frameTDRC->toString();
|
||||
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] == '-') {
|
||||
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] == ':') {
|
||||
ID3v2::TextIdentificationFrame *frameTIME = new ID3v2::TextIdentificationFrame("TIME", String::Latin1);
|
||||
frameTIME->setText(content.substr(11, 2) + content.substr(14, 2));
|
||||
frames->append(frameTIME);
|
||||
newFrames->append(frameTIME);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(frameTIPL || frameTMCL) {
|
||||
ID3v2::TextIdentificationFrame *frameIPLS = new ID3v2::TextIdentificationFrame("IPLS", String::Latin1);
|
||||
StringList people;
|
||||
if(frameTMCL) {
|
||||
StringList v24People = frameTMCL->fieldList();
|
||||
for(unsigned int i = 0; i + 1 < v24People.size(); i += 2) {
|
||||
people.append(v24People[i]);
|
||||
people.append(v24People[i+1]);
|
||||
}
|
||||
}
|
||||
if(frameTIPL) {
|
||||
StringList v24People = frameTIPL->fieldList();
|
||||
for(unsigned int i = 0; i + 1 < v24People.size(); i += 2) {
|
||||
people.append(v24People[i]);
|
||||
people.append(v24People[i+1]);
|
||||
}
|
||||
}
|
||||
frameIPLS->setText(people);
|
||||
frames->append(frameIPLS);
|
||||
newFrames->append(frameIPLS);
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector ID3v2::Tag::render(int 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
|
||||
// padding, but does not include the tag's header or footer.
|
||||
|
||||
if(version != 3 && version != 4) {
|
||||
debug("Unknown ID3v2 version, using ID3v2.4");
|
||||
version = 4;
|
||||
}
|
||||
|
||||
// TODO: Render the extended header.
|
||||
|
||||
// Downgrade the frames that ID3v2.3 doesn't support.
|
||||
|
||||
FrameList newFrames;
|
||||
newFrames.setAutoDelete(true);
|
||||
|
||||
FrameList frameList;
|
||||
if(version == 4) {
|
||||
frameList = d->frameList;
|
||||
}
|
||||
else {
|
||||
downgradeFrames(&frameList, &newFrames);
|
||||
}
|
||||
|
||||
// Reserve a 10-byte blank space for an ID3v2 tag header.
|
||||
|
||||
ByteVector tagData(Header::size(), '\0');
|
||||
|
||||
// Loop through the frames rendering them and adding them to the tagData.
|
||||
|
||||
for(FrameList::ConstIterator it = frameList.begin(); it != frameList.end(); it++) {
|
||||
(*it)->header()->setVersion(version);
|
||||
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()) {
|
||||
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");
|
||||
continue;
|
||||
}
|
||||
tagData.append(frameData);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the amount of padding, and append that to tagData.
|
||||
|
||||
long originalSize = d->header.tagSize();
|
||||
long paddingSize = originalSize - (tagData.size() - Header::size());
|
||||
|
||||
if(paddingSize <= 0) {
|
||||
paddingSize = MinPaddingSize;
|
||||
}
|
||||
else {
|
||||
// Padding won't increase beyond 1% of the file size or 1MB.
|
||||
|
||||
long threshold = d->file ? d->file->length() / 100 : 0;
|
||||
threshold = std::max(threshold, MinPaddingSize);
|
||||
threshold = std::min(threshold, MaxPaddingSize);
|
||||
|
||||
if(paddingSize > threshold)
|
||||
paddingSize = MinPaddingSize;
|
||||
}
|
||||
|
||||
tagData.resize(static_cast<unsigned int>(tagData.size() + paddingSize), '\0');
|
||||
|
||||
// Set the version and data size.
|
||||
d->header.setMajorVersion(version);
|
||||
d->header.setTagSize(tagData.size() - Header::size());
|
||||
|
||||
// TODO: This should eventually include d->footer->render().
|
||||
const ByteVector headerData = d->header.render();
|
||||
std::copy(headerData.begin(), headerData.end(), tagData.begin());
|
||||
|
||||
return tagData;
|
||||
}
|
||||
|
||||
Latin1StringHandler const *ID3v2::Tag::latin1StringHandler()
|
||||
{
|
||||
return stringHandler;
|
||||
}
|
||||
|
||||
void ID3v2::Tag::setLatin1StringHandler(const Latin1StringHandler *handler)
|
||||
{
|
||||
if(handler)
|
||||
stringHandler = handler;
|
||||
else
|
||||
stringHandler = &defaultStringHandler;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ID3v2::Tag::read()
|
||||
{
|
||||
if(!d->file)
|
||||
return;
|
||||
|
||||
if(!d->file->isOpen())
|
||||
return;
|
||||
|
||||
d->file->seek(d->tagOffset);
|
||||
d->header.setData(d->file->readBlock(Header::size()));
|
||||
|
||||
// If the tag size is 0, then this is an invalid tag (tags must contain at
|
||||
// least one frame)
|
||||
|
||||
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.
|
||||
// It leads to overwriting them with zero when saving the tag.
|
||||
|
||||
// This is a workaround for some faulty files that have duplicate ID3v2 tags.
|
||||
// Unfortunately, TagLib itself may write such duplicate tags until v1.10.
|
||||
|
||||
unsigned int extraSize = 0;
|
||||
|
||||
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()))
|
||||
break;
|
||||
|
||||
extraSize += Header(data).completeTagSize();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
ByteVector data = origData;
|
||||
|
||||
if(d->header.unsynchronisation() && d->header.majorVersion() <= 3)
|
||||
data = SynchData::decode(data);
|
||||
|
||||
unsigned int frameDataPosition = 0;
|
||||
unsigned int frameDataLength = data.size();
|
||||
|
||||
// check for extended header
|
||||
|
||||
if(d->header.extendedHeader()) {
|
||||
if(!d->extendedHeader)
|
||||
d->extendedHeader = new ExtendedHeader();
|
||||
d->extendedHeader->setData(data);
|
||||
if(d->extendedHeader->size() <= data.size()) {
|
||||
frameDataPosition += d->extendedHeader->size();
|
||||
frameDataLength -= d->extendedHeader->size();
|
||||
}
|
||||
}
|
||||
|
||||
// check for footer -- we don't actually need to parse it, as it *must*
|
||||
// contain the same data as the header, but we do need to account for its
|
||||
// size.
|
||||
|
||||
if(d->header.footerPresent() && Footer::size() <= frameDataLength)
|
||||
frameDataLength -= Footer::size();
|
||||
|
||||
// parse frames
|
||||
|
||||
// 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())) {
|
||||
|
||||
// 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()) {
|
||||
debug("Padding *and* a footer found. This is not allowed by the spec.");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
Frame *frame = d->factory->createFrame(data.mid(frameDataPosition),
|
||||
&d->header);
|
||||
|
||||
if(!frame)
|
||||
return;
|
||||
|
||||
// Checks to make sure that frame parsed correctly.
|
||||
|
||||
if(frame->size() <= 0) {
|
||||
delete frame;
|
||||
return;
|
||||
}
|
||||
|
||||
frameDataPosition += frame->size() + Frame::headerSize(d->header.majorVersion());
|
||||
addFrame(frame);
|
||||
}
|
||||
|
||||
d->factory->rebuildAggregateFrames(this);
|
||||
}
|
||||
|
||||
void ID3v2::Tag::setTextFrame(const ByteVector &id, const String &value)
|
||||
{
|
||||
if(value.isEmpty()) {
|
||||
removeFrames(id);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!d->frameListMap[id].isEmpty())
|
||||
d->frameListMap[id].front()->setText(value);
|
||||
else {
|
||||
const String::Type encoding = d->factory->defaultTextEncoding();
|
||||
TextIdentificationFrame *f = new TextIdentificationFrame(id, encoding);
|
||||
addFrame(f);
|
||||
f->setText(value);
|
||||
}
|
||||
}
|
||||
412
3rdparty/taglib/mpeg/id3v2/id3v2tag.h
vendored
Normal file
412
3rdparty/taglib/mpeg/id3v2/id3v2tag.h
vendored
Normal file
@@ -0,0 +1,412 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_ID3V2TAG_H
|
||||
#define TAGLIB_ID3V2TAG_H
|
||||
|
||||
#include "tag.h"
|
||||
#include "tbytevector.h"
|
||||
#include "tstring.h"
|
||||
#include "tlist.h"
|
||||
#include "tmap.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
#include "id3v2framefactory.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
class File;
|
||||
|
||||
//! An ID3v2 implementation
|
||||
|
||||
/*!
|
||||
* This is a relatively complete and flexible framework for working with ID3v2
|
||||
* tags.
|
||||
*
|
||||
* \see ID3v2::Tag
|
||||
*/
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
class Header;
|
||||
class ExtendedHeader;
|
||||
class Footer;
|
||||
|
||||
typedef List<Frame *> FrameList;
|
||||
typedef Map<ByteVector, FrameList> FrameListMap;
|
||||
|
||||
//! 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
|
||||
* Windows-1252 for western languages, Shift_JIS for Japanese and so on.
|
||||
*
|
||||
* Here is an option to read such tags by subclassing this class,
|
||||
* reimplementing parse() and setting your reimplementation as the default
|
||||
* with ID3v2::Tag::setStringHandler().
|
||||
*
|
||||
* \note Writing non-ISO-8859-1 tags is not implemented intentionally.
|
||||
* Use UTF-16 or UTF-8 instead.
|
||||
*
|
||||
* \see ID3v2::Tag::setStringHandler()
|
||||
*/
|
||||
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;
|
||||
};
|
||||
|
||||
//! 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
|
||||
* read() and parse() protected methods, it provides the most basic level of
|
||||
* parsing. In these methods the ID3v2 tag is extracted from the file and
|
||||
* split into data components.
|
||||
*
|
||||
* ID3v2 tags have several parts, TagLib attempts to provide an interface
|
||||
* for them all. header(), footer() and extendedHeader() correspond to those
|
||||
* data structures in the ID3v2 standard and the APIs for the classes that
|
||||
* they return attempt to reflect this.
|
||||
*
|
||||
* Also ID3v2 tags are built up from a list of frames, which are in turn
|
||||
* have a header and a list of fields. TagLib provides two ways of accessing
|
||||
* the list of frames that are in a given ID3v2 tag. The first is simply
|
||||
* via the frameList() method. This is just a list of pointers to the frames.
|
||||
* The second is a map from the frame type -- i.e. "COMM" for comments -- and
|
||||
* a list of frames of that type. (In some cases ID3v2 allows for multiple
|
||||
* frames of the same type, hence this being a map to a list rather than just
|
||||
* a map to an individual frame.)
|
||||
*
|
||||
* More information on the structure of frames can be found in the ID3v2::Frame
|
||||
* class.
|
||||
*
|
||||
* read() and parse() pass binary data to the other ID3v2 class structures,
|
||||
* they do not handle parsing of flags or fields, for instance. Those are
|
||||
* handled by similar functions within those classes.
|
||||
*
|
||||
* \note All pointers to data structures within the tag will become invalid
|
||||
* when the tag is destroyed.
|
||||
*
|
||||
* \warning Dealing with the nasty details of ID3v2 is not for the faint of
|
||||
* heart and should not be done without much meditation on the spec. It's
|
||||
* rather long, but if you're planning on messing with this class and others
|
||||
* that deal with the details of ID3v2 (rather than the nice, safe, abstract
|
||||
* TagLib::Tag and friends), it's worth your time to familiarize yourself
|
||||
* with said spec (which is distributed with the TagLib sources). TagLib
|
||||
* tries to do most of the work, but with a little luck, you can still
|
||||
* convince it to generate invalid ID3v2 tags. The APIs for ID3v2 assume a
|
||||
* working knowledge of ID3v2 structure. You're been warned.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT Tag : public TagLib::Tag
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* Constructs an empty ID3v2 tag.
|
||||
*
|
||||
* \note You must create at least one frame for this tag to be valid.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* \note You should be able to ignore the \a factory parameter in almost
|
||||
* all situations. You would want to specify your own FrameFactory
|
||||
* subclass in the case that you are extending TagLib to support additional
|
||||
* frame types, which would be incorporated into your factory.
|
||||
*
|
||||
* \see FrameFactory
|
||||
*/
|
||||
Tag(File *file, long tagOffset,
|
||||
const FrameFactory *factory = FrameFactory::instance());
|
||||
|
||||
/*!
|
||||
* Destroys this Tag instance.
|
||||
*/
|
||||
virtual ~Tag();
|
||||
|
||||
// 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 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;
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the tag's header.
|
||||
*/
|
||||
Header *header() const;
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the tag's extended header or null if there is no
|
||||
* extended header.
|
||||
*/
|
||||
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
|
||||
* nothing useful to be retrieved from the footer, but well, again, I'm
|
||||
* prone to change my mind, so this gets to stay around until near a
|
||||
* release.
|
||||
*/
|
||||
Footer *footer() const;
|
||||
|
||||
/*!
|
||||
* Returns a reference to the frame list map. This is an FrameListMap of
|
||||
* all of the frames in the tag.
|
||||
*
|
||||
* This is the most convenient structure for accessing the tag's frames.
|
||||
* Many frame types allow multiple instances of the same frame type so this
|
||||
* is a map of lists. In most cases however there will only be a single
|
||||
* frame of a certain type.
|
||||
*
|
||||
* Let's say for instance that you wanted to access the frame for total
|
||||
* beats per minute -- the TBPM frame.
|
||||
*
|
||||
* \code
|
||||
* TagLib::MPEG::File f("foo.mp3");
|
||||
*
|
||||
* // Check to make sure that it has an ID3v2 tag
|
||||
*
|
||||
* if(f.ID3v2Tag()) {
|
||||
*
|
||||
* // Get the list of frames for a specific frame type
|
||||
*
|
||||
* TagLib::ID3v2::FrameList l = f.ID3v2Tag()->frameListMap()["TBPM"];
|
||||
*
|
||||
* if(!l.isEmpty())
|
||||
* std::cout << l.front()->toString() << std::endl;
|
||||
* }
|
||||
*
|
||||
* \endcode
|
||||
*
|
||||
* \warning You should not modify this data structure directly, instead
|
||||
* use addFrame() and removeFrame().
|
||||
*
|
||||
* \see frameList()
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* This can be useful if for example you want iterate over the tag's frames
|
||||
* in the order that they occur in the tag.
|
||||
*
|
||||
* \warning You should not modify this data structure directly, instead
|
||||
* use addFrame() and removeFrame().
|
||||
*/
|
||||
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:
|
||||
*
|
||||
* \code
|
||||
* frameListMap()[frameID];
|
||||
* \endcode
|
||||
*
|
||||
* \see frameListMap()
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* 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:
|
||||
* - if ID3v2 frame ID is known by Frame::frameIDToKey(), the returned
|
||||
* key is used
|
||||
* - if the frame ID is "TXXX" (user text frame), the description() is
|
||||
* used as key
|
||||
* - if the frame ID is "WXXX" (user url frame),
|
||||
* - if the description is empty or "URL", the key "URL" is used
|
||||
* - otherwise, the key "URL:<description>" is used;
|
||||
* - if the frame ID is "COMM" (comments frame),
|
||||
* - if the description is empty or "COMMENT", the key "COMMENT"
|
||||
* is used
|
||||
* - otherwise, the key "COMMENT:<description>" is used;
|
||||
* - if the frame ID is "USLT" (unsynchronized lyrics),
|
||||
* - if the description is empty or "LYRICS", the key "LYRICS" is used
|
||||
* - otherwise, the key "LYRICS:<description>" is used;
|
||||
* - if the frame ID is "TIPL" (involved peoples list), and if all the
|
||||
* roles defined in the frame are known in TextIdentificationFrame::involvedPeopleMap(),
|
||||
* then "<role>=<name>" will be contained in the returned obejct for each
|
||||
* - if the frame ID is "TMCL" (musician credit list), then
|
||||
* "PERFORMER:<instrument>=<name>" will be contained in the returned
|
||||
* PropertyMap for each defined musician
|
||||
* In any other case, the unsupportedData() of the returned object will contain
|
||||
* the frame's ID and, in case of a frame ID which is allowed to appear more than
|
||||
* once, the description, separated by a "/".
|
||||
*
|
||||
*/
|
||||
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:
|
||||
* - a four-character frame ID, if the ID3 specification allows only one
|
||||
* frame with that ID (thus, the frame is uniquely determined)
|
||||
* - frameID + "/" + description(), when the ID is one of "TXXX", "WXXX",
|
||||
* "COMM", or "USLT",
|
||||
* - "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);
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- import function.
|
||||
* See the comments in properties().
|
||||
*/
|
||||
PropertyMap setProperties(const PropertyMap &);
|
||||
|
||||
/*!
|
||||
* Render the tag back to binary data, suitable to be written to disk.
|
||||
*/
|
||||
ByteVector render() const;
|
||||
|
||||
/*!
|
||||
* Render the tag back to binary data, suitable to be written to disk.
|
||||
*
|
||||
* The \a version parameter specifies the version of the rendered
|
||||
* ID3v2 tag. It can be either 4 or 3.
|
||||
*/
|
||||
// BIC: combine with the above method
|
||||
ByteVector render(int 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();
|
||||
|
||||
/*!
|
||||
* 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
|
||||
* released and default ISO-8859-1 handler is restored.
|
||||
*
|
||||
* \note The caller is responsible for deleting the previous handler
|
||||
* as needed after it is released.
|
||||
*
|
||||
* \see Latin1StringHandler
|
||||
*/
|
||||
static void setLatin1StringHandler(const Latin1StringHandler *handler);
|
||||
|
||||
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();
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* 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 downgradeFrames(FrameList *existingFrames, FrameList *newFrames) const;
|
||||
|
||||
private:
|
||||
Tag(const Tag &);
|
||||
Tag &operator=(const Tag &);
|
||||
|
||||
class TagPrivate;
|
||||
TagPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
575
3rdparty/taglib/mpeg/mpegfile.cpp
vendored
Normal file
575
3rdparty/taglib/mpeg/mpegfile.cpp
vendored
Normal file
@@ -0,0 +1,575 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tagunion.h>
|
||||
#include <tagutils.h>
|
||||
#include <id3v2tag.h>
|
||||
#include <id3v2header.h>
|
||||
#include <id3v1tag.h>
|
||||
#include <apefooter.h>
|
||||
#include <apetag.h>
|
||||
#include <tdebug.h>
|
||||
|
||||
#include "mpegfile.h"
|
||||
#include "mpegheader.h"
|
||||
#include "mpegutils.h"
|
||||
#include "tpropertymap.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
namespace
|
||||
{
|
||||
enum { ID3v2Index = 0, APEIndex = 1, ID3v1Index = 2 };
|
||||
}
|
||||
|
||||
class MPEG::File::FilePrivate
|
||||
{
|
||||
public:
|
||||
FilePrivate(const ID3v2::FrameFactory *frameFactory = ID3v2::FrameFactory::instance()) :
|
||||
ID3v2FrameFactory(frameFactory),
|
||||
ID3v2Location(-1),
|
||||
ID3v2OriginalSize(0),
|
||||
APELocation(-1),
|
||||
APEOriginalSize(0),
|
||||
ID3v1Location(-1),
|
||||
properties(0) {}
|
||||
|
||||
~FilePrivate()
|
||||
{
|
||||
delete properties;
|
||||
}
|
||||
|
||||
const ID3v2::FrameFactory *ID3v2FrameFactory;
|
||||
|
||||
long ID3v2Location;
|
||||
long ID3v2OriginalSize;
|
||||
|
||||
long APELocation;
|
||||
long APEOriginalSize;
|
||||
|
||||
long ID3v1Location;
|
||||
|
||||
TagUnion tag;
|
||||
|
||||
Properties *properties;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// static members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace
|
||||
{
|
||||
// Dummy file class to make a stream work with MPEG::Header.
|
||||
|
||||
class AdapterFile : public TagLib::File
|
||||
{
|
||||
public:
|
||||
AdapterFile(IOStream *stream) : File(stream) {}
|
||||
|
||||
Tag *tag() const { return 0; }
|
||||
AudioProperties *audioProperties() const { return 0; }
|
||||
bool save() { return false; }
|
||||
};
|
||||
}
|
||||
|
||||
bool MPEG::File::isSupported(IOStream *stream)
|
||||
{
|
||||
if(!stream || !stream->isOpen())
|
||||
return false;
|
||||
|
||||
// An MPEG file has MPEG frame headers. An ID3v2 tag may precede.
|
||||
|
||||
// MPEG frame headers are really confusing with irrelevant binary data.
|
||||
// So we check if a frame header is really valid.
|
||||
|
||||
long headerOffset;
|
||||
const ByteVector buffer = Utils::readHeader(stream, bufferSize(), true, &headerOffset);
|
||||
|
||||
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)) {
|
||||
const Header header(&file, headerOffset + i, true);
|
||||
if(header.isValid()) {
|
||||
stream->seek(originalPosition);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stream->seek(originalPosition);
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MPEG::File::File(FileName file, bool readProperties, Properties::ReadStyle) :
|
||||
TagLib::File(file),
|
||||
d(new FilePrivate())
|
||||
{
|
||||
if(isOpen())
|
||||
read(readProperties);
|
||||
}
|
||||
|
||||
MPEG::File::File(FileName file, ID3v2::FrameFactory *frameFactory,
|
||||
bool readProperties, Properties::ReadStyle) :
|
||||
TagLib::File(file),
|
||||
d(new FilePrivate(frameFactory))
|
||||
{
|
||||
if(isOpen())
|
||||
read(readProperties);
|
||||
}
|
||||
|
||||
MPEG::File::File(IOStream *stream, ID3v2::FrameFactory *frameFactory,
|
||||
bool readProperties, Properties::ReadStyle) :
|
||||
TagLib::File(stream),
|
||||
d(new FilePrivate(frameFactory))
|
||||
{
|
||||
if(isOpen())
|
||||
read(readProperties);
|
||||
}
|
||||
|
||||
MPEG::File::~File()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
TagLib::Tag *MPEG::File::tag() const
|
||||
{
|
||||
return &d->tag;
|
||||
}
|
||||
|
||||
PropertyMap MPEG::File::properties() const
|
||||
{
|
||||
return d->tag.properties();
|
||||
}
|
||||
|
||||
void MPEG::File::removeUnsupportedProperties(const StringList &properties)
|
||||
{
|
||||
d->tag.removeUnsupportedProperties(properties);
|
||||
}
|
||||
|
||||
PropertyMap MPEG::File::setProperties(const PropertyMap &properties)
|
||||
{
|
||||
// update ID3v1 tag if it exists, but ignore the return value
|
||||
|
||||
if(ID3v1Tag())
|
||||
ID3v1Tag()->setProperties(properties);
|
||||
|
||||
return ID3v2Tag(true)->setProperties(properties);
|
||||
}
|
||||
|
||||
MPEG::Properties *MPEG::File::audioProperties() const
|
||||
{
|
||||
return d->properties;
|
||||
}
|
||||
|
||||
bool MPEG::File::save()
|
||||
{
|
||||
return save(AllTags);
|
||||
}
|
||||
|
||||
bool MPEG::File::save(int tags)
|
||||
{
|
||||
return save(tags, true);
|
||||
}
|
||||
|
||||
bool MPEG::File::save(int tags, bool stripOthers)
|
||||
{
|
||||
return save(tags, stripOthers, 4);
|
||||
}
|
||||
|
||||
bool MPEG::File::save(int tags, bool stripOthers, int id3v2Version)
|
||||
{
|
||||
return save(tags, stripOthers, id3v2Version, true);
|
||||
}
|
||||
|
||||
bool MPEG::File::save(int tags, bool stripOthers, int id3v2Version, bool duplicateTags)
|
||||
{
|
||||
if(readOnly()) {
|
||||
debug("MPEG::File::save() -- File is read only.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create the tags if we've been asked to.
|
||||
|
||||
if(duplicateTags) {
|
||||
|
||||
// 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() && !(stripOthers && !(tags & ID3v1)))
|
||||
Tag::duplicate(ID3v1Tag(), ID3v2Tag(true), false);
|
||||
|
||||
if((tags & ID3v1) && d->tag[ID3v2Index] && !(stripOthers && !(tags & ID3v2)))
|
||||
Tag::duplicate(ID3v2Tag(), ID3v1Tag(true), false);
|
||||
}
|
||||
|
||||
// Remove all the tags not going to be saved.
|
||||
|
||||
if(stripOthers)
|
||||
strip(~tags, false);
|
||||
|
||||
if(ID3v2 & tags) {
|
||||
|
||||
if(ID3v2Tag() && !ID3v2Tag()->isEmpty()) {
|
||||
|
||||
// ID3v2 tag is not empty. Update the old one or create a new one.
|
||||
|
||||
if(d->ID3v2Location < 0)
|
||||
d->ID3v2Location = 0;
|
||||
|
||||
const ByteVector data = ID3v2Tag()->render(id3v2Version);
|
||||
insert(data, d->ID3v2Location, d->ID3v2OriginalSize);
|
||||
|
||||
if(d->APELocation >= 0)
|
||||
d->APELocation += (static_cast<long>(data.size()) - d->ID3v2OriginalSize);
|
||||
|
||||
if(d->ID3v1Location >= 0)
|
||||
d->ID3v1Location += (static_cast<long>(data.size()) - d->ID3v2OriginalSize);
|
||||
|
||||
d->ID3v2OriginalSize = data.size();
|
||||
}
|
||||
else {
|
||||
|
||||
// ID3v2 tag is empty. Remove the old one.
|
||||
|
||||
strip(ID3v2, false);
|
||||
}
|
||||
}
|
||||
|
||||
if(ID3v1 & tags) {
|
||||
|
||||
if(ID3v1Tag() && !ID3v1Tag()->isEmpty()) {
|
||||
|
||||
// ID3v1 tag is not empty. Update the old one or create a new one.
|
||||
|
||||
if(d->ID3v1Location >= 0) {
|
||||
seek(d->ID3v1Location);
|
||||
}
|
||||
else {
|
||||
seek(0, End);
|
||||
d->ID3v1Location = tell();
|
||||
}
|
||||
|
||||
writeBlock(ID3v1Tag()->render());
|
||||
}
|
||||
else {
|
||||
|
||||
// ID3v1 tag is empty. Remove the old one.
|
||||
|
||||
strip(ID3v1, false);
|
||||
}
|
||||
}
|
||||
|
||||
if(APE & tags) {
|
||||
|
||||
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)
|
||||
d->APELocation = d->ID3v1Location;
|
||||
else
|
||||
d->APELocation = length();
|
||||
}
|
||||
|
||||
const ByteVector data = APETag()->render();
|
||||
insert(data, d->APELocation, d->APEOriginalSize);
|
||||
|
||||
if(d->ID3v1Location >= 0)
|
||||
d->ID3v1Location += (static_cast<long>(data.size()) - d->APEOriginalSize);
|
||||
|
||||
d->APEOriginalSize = data.size();
|
||||
}
|
||||
else {
|
||||
|
||||
// APE tag is empty. Remove the old one.
|
||||
|
||||
strip(APE, false);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ID3v2::Tag *MPEG::File::ID3v2Tag(bool create)
|
||||
{
|
||||
return d->tag.access<ID3v2::Tag>(ID3v2Index, create);
|
||||
}
|
||||
|
||||
ID3v1::Tag *MPEG::File::ID3v1Tag(bool create)
|
||||
{
|
||||
return d->tag.access<ID3v1::Tag>(ID3v1Index, create);
|
||||
}
|
||||
|
||||
APE::Tag *MPEG::File::APETag(bool create)
|
||||
{
|
||||
return d->tag.access<APE::Tag>(APEIndex, create);
|
||||
}
|
||||
|
||||
bool MPEG::File::strip(int tags)
|
||||
{
|
||||
return strip(tags, true);
|
||||
}
|
||||
|
||||
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) {
|
||||
removeBlock(d->ID3v2Location, d->ID3v2OriginalSize);
|
||||
|
||||
if(d->APELocation >= 0)
|
||||
d->APELocation -= d->ID3v2OriginalSize;
|
||||
|
||||
if(d->ID3v1Location >= 0)
|
||||
d->ID3v1Location -= d->ID3v2OriginalSize;
|
||||
|
||||
d->ID3v2Location = -1;
|
||||
d->ID3v2OriginalSize = 0;
|
||||
|
||||
if(freeMemory)
|
||||
d->tag.set(ID3v2Index, 0);
|
||||
}
|
||||
|
||||
if((tags & ID3v1) && d->ID3v1Location >= 0) {
|
||||
truncate(d->ID3v1Location);
|
||||
|
||||
d->ID3v1Location = -1;
|
||||
|
||||
if(freeMemory)
|
||||
d->tag.set(ID3v1Index, 0);
|
||||
}
|
||||
|
||||
if((tags & APE) && d->APELocation >= 0) {
|
||||
removeBlock(d->APELocation, d->APEOriginalSize);
|
||||
|
||||
if(d->ID3v1Location >= 0)
|
||||
d->ID3v1Location -= d->APEOriginalSize;
|
||||
|
||||
d->APELocation = -1;
|
||||
d->APEOriginalSize = 0;
|
||||
|
||||
if(freeMemory)
|
||||
d->tag.set(APEIndex, 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MPEG::File::setID3v2FrameFactory(const ID3v2::FrameFactory *factory)
|
||||
{
|
||||
d->ID3v2FrameFactory = factory;
|
||||
}
|
||||
|
||||
long MPEG::File::nextFrameOffset(long position)
|
||||
{
|
||||
ByteVector frameSyncBytes(2, '\0');
|
||||
|
||||
while(true) {
|
||||
seek(position);
|
||||
const ByteVector buffer = readBlock(bufferSize());
|
||||
if(buffer.isEmpty())
|
||||
return -1;
|
||||
|
||||
for(unsigned int i = 0; i < buffer.size(); ++i) {
|
||||
frameSyncBytes[0] = frameSyncBytes[1];
|
||||
frameSyncBytes[1] = buffer[i];
|
||||
if(isFrameSync(frameSyncBytes)) {
|
||||
const Header header(this, position + i - 1, true);
|
||||
if(header.isValid())
|
||||
return position + i - 1;
|
||||
}
|
||||
}
|
||||
|
||||
position += bufferSize();
|
||||
}
|
||||
}
|
||||
|
||||
long MPEG::File::previousFrameOffset(long position)
|
||||
{
|
||||
ByteVector frameSyncBytes(2, '\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) {
|
||||
frameSyncBytes[1] = frameSyncBytes[0];
|
||||
frameSyncBytes[0] = buffer[i];
|
||||
if(isFrameSync(frameSyncBytes)) {
|
||||
const Header header(this, position + i, true);
|
||||
if(header.isValid())
|
||||
return position + i + header.frameLength();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
long MPEG::File::firstFrameOffset()
|
||||
{
|
||||
long position = 0;
|
||||
|
||||
if(hasID3v2Tag())
|
||||
position = d->ID3v2Location + ID3v2Tag()->header()->completeTagSize();
|
||||
|
||||
return nextFrameOffset(position);
|
||||
}
|
||||
|
||||
long MPEG::File::lastFrameOffset()
|
||||
{
|
||||
long position;
|
||||
|
||||
if(hasAPETag())
|
||||
position = d->APELocation - 1;
|
||||
else if(hasID3v1Tag())
|
||||
position = d->ID3v1Location - 1;
|
||||
else
|
||||
position = length();
|
||||
|
||||
return previousFrameOffset(position);
|
||||
}
|
||||
|
||||
bool MPEG::File::hasID3v1Tag() const
|
||||
{
|
||||
return (d->ID3v1Location >= 0);
|
||||
}
|
||||
|
||||
bool MPEG::File::hasID3v2Tag() const
|
||||
{
|
||||
return (d->ID3v2Location >= 0);
|
||||
}
|
||||
|
||||
bool MPEG::File::hasAPETag() const
|
||||
{
|
||||
return (d->APELocation >= 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void MPEG::File::read(bool readProperties)
|
||||
{
|
||||
// Look for an ID3v2 tag
|
||||
|
||||
d->ID3v2Location = findID3v2();
|
||||
|
||||
if(d->ID3v2Location >= 0) {
|
||||
d->tag.set(ID3v2Index, new ID3v2::Tag(this, d->ID3v2Location, d->ID3v2FrameFactory));
|
||||
d->ID3v2OriginalSize = ID3v2Tag()->header()->completeTagSize();
|
||||
}
|
||||
|
||||
// Look for an ID3v1 tag
|
||||
|
||||
d->ID3v1Location = Utils::findID3v1(this);
|
||||
|
||||
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) {
|
||||
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)
|
||||
d->properties = new Properties(this);
|
||||
|
||||
// Make sure that we have our default tag types available.
|
||||
|
||||
ID3v2Tag(true);
|
||||
ID3v1Tag(true);
|
||||
}
|
||||
|
||||
long MPEG::File::findID3v2()
|
||||
{
|
||||
if(!isValid())
|
||||
return -1;
|
||||
|
||||
// An ID3v2 tag or MPEG frame is most likely be at the beginning of the file.
|
||||
|
||||
const ByteVector headerID = ID3v2::Header::fileIdentifier();
|
||||
|
||||
seek(0);
|
||||
if(readBlock(headerID.size()) == headerID)
|
||||
return 0;
|
||||
|
||||
const Header firstHeader(this, 0, true);
|
||||
if(firstHeader.isValid())
|
||||
return -1;
|
||||
|
||||
// Look for an ID3v2 tag until reaching the first valid MPEG frame.
|
||||
|
||||
ByteVector frameSyncBytes(2, '\0');
|
||||
ByteVector tagHeaderBytes(3, '\0');
|
||||
long position = 0;
|
||||
|
||||
while(true) {
|
||||
seek(position);
|
||||
const ByteVector buffer = readBlock(bufferSize());
|
||||
if(buffer.isEmpty())
|
||||
return -1;
|
||||
|
||||
for(unsigned int i = 0; i < buffer.size(); ++i) {
|
||||
frameSyncBytes[0] = frameSyncBytes[1];
|
||||
frameSyncBytes[1] = buffer[i];
|
||||
if(isFrameSync(frameSyncBytes)) {
|
||||
const Header header(this, position + i - 1, true);
|
||||
if(header.isValid())
|
||||
return -1;
|
||||
}
|
||||
|
||||
tagHeaderBytes[0] = tagHeaderBytes[1];
|
||||
tagHeaderBytes[1] = tagHeaderBytes[2];
|
||||
tagHeaderBytes[2] = buffer[i];
|
||||
if(tagHeaderBytes == headerID)
|
||||
return position + i - 2;
|
||||
}
|
||||
|
||||
position += bufferSize();
|
||||
}
|
||||
}
|
||||
395
3rdparty/taglib/mpeg/mpegfile.h
vendored
Normal file
395
3rdparty/taglib/mpeg/mpegfile.h
vendored
Normal file
@@ -0,0 +1,395 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_MPEGFILE_H
|
||||
#define TAGLIB_MPEGFILE_H
|
||||
|
||||
#include "taglib_export.h"
|
||||
#include "tfile.h"
|
||||
#include "tag.h"
|
||||
|
||||
#include "mpegproperties.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 { class Tag; class FrameFactory; }
|
||||
namespace ID3v1 { class Tag; }
|
||||
namespace APE { class Tag; }
|
||||
|
||||
//! An implementation of TagLib::File with MPEG (MP3) specific methods
|
||||
|
||||
namespace 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 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
|
||||
};
|
||||
|
||||
/*!
|
||||
* Constructs an MPEG file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read.
|
||||
*
|
||||
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||
*
|
||||
* \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);
|
||||
|
||||
/*!
|
||||
* Constructs an MPEG file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read.
|
||||
*
|
||||
* If this file contains and ID3v2 tag the frames will be created using
|
||||
* \a frameFactory.
|
||||
*
|
||||
* \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);
|
||||
|
||||
/*!
|
||||
* Constructs an MPEG file from \a stream. If \a readProperties is true the
|
||||
* file's audio properties will also be read.
|
||||
*
|
||||
* \note TagLib will *not* take ownership of the stream, the caller is
|
||||
* responsible for deleting it after the File object.
|
||||
*
|
||||
* If this file contains and ID3v2 tag the frames will be created using
|
||||
* \a frameFactory.
|
||||
*
|
||||
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(IOStream *stream, ID3v2::FrameFactory *frameFactory,
|
||||
bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the 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,
|
||||
* the information from the ID3v2 tag will be returned.
|
||||
*
|
||||
* If you would like more granular control over the content of the tags,
|
||||
* with the concession of generality, use the tag-type specific calls.
|
||||
*
|
||||
* \note As this tag is not implemented as an ID3v2 tag or an ID3v1 tag,
|
||||
* but a union of the two this pointer may not be cast to the specific
|
||||
* tag types.
|
||||
*
|
||||
* \see ID3v1Tag()
|
||||
* \see ID3v2Tag()
|
||||
* \see APETag()
|
||||
*/
|
||||
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;
|
||||
|
||||
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.
|
||||
* If an ID3v1 tag exists, it will be updated as well, within the
|
||||
* limitations of that format.
|
||||
* The returned PropertyMap refers to the ID3v2 tag only.
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* 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.
|
||||
*
|
||||
* If neither exists or if both tags are empty, this will strip the tags
|
||||
* from the file.
|
||||
*
|
||||
* This is the same as calling save(AllTags);
|
||||
*
|
||||
* If you would like more granular control over the content of the tags,
|
||||
* with the concession of generality, use parameterized save call below.
|
||||
*
|
||||
* \see save(int tags)
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* This strips all tags not included in the mask, but does not modify them
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* 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.
|
||||
*
|
||||
* If \a stripOthers is true this strips all tags not included in the mask,
|
||||
* but does not modify them in memory, so later calls to save() which make
|
||||
* use of these tags will remain valid. This also strips empty tags.
|
||||
*/
|
||||
// BIC: combine with the above method
|
||||
bool save(int tags, bool stripOthers);
|
||||
|
||||
/*!
|
||||
* 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.
|
||||
*
|
||||
* If \a stripOthers is true this strips all tags not included in the mask,
|
||||
* but does not modify them in memory, so later calls to save() which make
|
||||
* use of these tags will remain valid. This also strips empty tags.
|
||||
*
|
||||
* The \a id3v2Version parameter specifies the version of the saved
|
||||
* ID3v2 tag. It can be either 4 or 3.
|
||||
*/
|
||||
// BIC: combine with the above method
|
||||
bool save(int tags, bool stripOthers, int id3v2Version);
|
||||
|
||||
/*!
|
||||
* 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.
|
||||
*
|
||||
* If \a stripOthers is true this strips all tags not included in the mask,
|
||||
* but does not modify them in memory, so later calls to save() which make
|
||||
* use of these tags will remain valid. This also strips empty tags.
|
||||
*
|
||||
* The \a id3v2Version parameter specifies the version of the saved
|
||||
* ID3v2 tag. It can be either 4 or 3.
|
||||
*
|
||||
* If \a duplicateTags is true and at least one tag -- ID3v1 or ID3v2 --
|
||||
* exists this will duplicate its content into the other tag.
|
||||
*/
|
||||
// BIC: combine with the above method
|
||||
bool save(int tags, bool stripOthers, int id3v2Version, bool duplicateTags);
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the ID3v2 tag of the file.
|
||||
*
|
||||
* If \a create is false (the default) this may return a null pointer
|
||||
* if there is no valid ID3v2 tag. If \a create is true it will create
|
||||
* an ID3v2 tag if one does not exist and returns a valid pointer.
|
||||
*
|
||||
* \note This may return a valid pointer regardless of whether or not the
|
||||
* file on disk has an ID3v2 tag. Use hasID3v2Tag() to check if the file
|
||||
* on disk actually has an ID3v2 tag.
|
||||
*
|
||||
* \note The Tag <b>is still</b> owned by the MPEG::File and should not be
|
||||
* deleted by the user. It will be deleted when the file (object) is
|
||||
* destroyed.
|
||||
*
|
||||
* \see hasID3v2Tag()
|
||||
*/
|
||||
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
|
||||
* if there is no valid ID3v1 tag. If \a create is true it will create
|
||||
* an ID3v1 tag if one does not exist and returns a valid pointer.
|
||||
*
|
||||
* \note This may return a valid pointer regardless of whether or not the
|
||||
* file on disk has an ID3v1 tag. Use hasID3v1Tag() to check if the file
|
||||
* on disk actually has an ID3v1 tag.
|
||||
*
|
||||
* \note The Tag <b>is still</b> owned by the MPEG::File and should not be
|
||||
* deleted by the user. It will be deleted when the file (object) is
|
||||
* destroyed.
|
||||
*
|
||||
* \see hasID3v1Tag()
|
||||
*/
|
||||
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
|
||||
* if there is no valid APE tag. If \a create is true it will create
|
||||
* an APE tag if one does not exist and returns a valid pointer.
|
||||
*
|
||||
* \note This may return a valid pointer regardless of whether or not the
|
||||
* file on disk has an APE tag. Use hasAPETag() to check if the file
|
||||
* on disk actually has an APE tag.
|
||||
*
|
||||
* \note The Tag <b>is still</b> owned by the MPEG::File and should not be
|
||||
* deleted by the user. It will be deleted when the file (object) is
|
||||
* destroyed.
|
||||
*
|
||||
* \see hasAPETag()
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* This is equivalent to strip(tags, true)
|
||||
*
|
||||
* \note This will also invalidate pointers to the ID3 and APE tags
|
||||
* as their memory will be freed.
|
||||
*
|
||||
* \note This will update the file immediately.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* If \a freeMemory is true the ID3 and APE tags will be deleted and
|
||||
* pointers to them will be invalidated.
|
||||
*
|
||||
* \note This will update the file immediately.
|
||||
*/
|
||||
// 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
|
||||
*/
|
||||
void setID3v2FrameFactory(const ID3v2::FrameFactory *factory);
|
||||
|
||||
/*!
|
||||
* Returns the position in the file of the first MPEG frame.
|
||||
*/
|
||||
long firstFrameOffset();
|
||||
|
||||
/*!
|
||||
* Returns the position in the file of the next MPEG frame,
|
||||
* using the current position as start
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* Returns the position in the file of the last MPEG frame.
|
||||
*/
|
||||
long lastFrameOffset();
|
||||
|
||||
/*!
|
||||
* Returns whether or not the file on disk actually has an ID3v1 tag.
|
||||
*
|
||||
* \see ID3v1Tag()
|
||||
*/
|
||||
bool hasID3v1Tag() const;
|
||||
|
||||
/*!
|
||||
* Returns whether or not the file on disk actually has an ID3v2 tag.
|
||||
*
|
||||
* \see ID3v2Tag()
|
||||
*/
|
||||
bool hasID3v2Tag() const;
|
||||
|
||||
/*!
|
||||
* Returns whether or not the file on disk actually has an APE tag.
|
||||
*
|
||||
* \see APETag()
|
||||
*/
|
||||
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);
|
||||
|
||||
private:
|
||||
File(const File &);
|
||||
File &operator=(const File &);
|
||||
|
||||
void read(bool readProperties);
|
||||
long findID3v2();
|
||||
|
||||
class FilePrivate;
|
||||
FilePrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
322
3rdparty/taglib/mpeg/mpegheader.cpp
vendored
Normal file
322
3rdparty/taglib/mpeg/mpegheader.cpp
vendored
Normal file
@@ -0,0 +1,322 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tbytevector.h>
|
||||
#include <tstring.h>
|
||||
#include <tfile.h>
|
||||
#include <tdebug.h>
|
||||
#include <trefcounter.h>
|
||||
|
||||
#include "mpegheader.h"
|
||||
#include "mpegutils.h"
|
||||
|
||||
using namespace 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) {}
|
||||
|
||||
bool isValid;
|
||||
Version version;
|
||||
int layer;
|
||||
bool protectionEnabled;
|
||||
int bitrate;
|
||||
int sampleRate;
|
||||
bool isPadded;
|
||||
ChannelMode channelMode;
|
||||
bool isCopyrighted;
|
||||
bool isOriginal;
|
||||
int frameLength;
|
||||
int samplesPerFrame;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MPEG::Header::Header(const ByteVector &data) :
|
||||
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())
|
||||
{
|
||||
parse(file, offset, checkLength);
|
||||
}
|
||||
|
||||
MPEG::Header::Header(const Header &h) :
|
||||
d(h.d)
|
||||
{
|
||||
d->ref();
|
||||
}
|
||||
|
||||
MPEG::Header::~Header()
|
||||
{
|
||||
if(d->deref())
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool MPEG::Header::isValid() const
|
||||
{
|
||||
return d->isValid;
|
||||
}
|
||||
|
||||
MPEG::Header::Version MPEG::Header::version() const
|
||||
{
|
||||
return d->version;
|
||||
}
|
||||
|
||||
int MPEG::Header::layer() const
|
||||
{
|
||||
return d->layer;
|
||||
}
|
||||
|
||||
bool MPEG::Header::protectionEnabled() const
|
||||
{
|
||||
return d->protectionEnabled;
|
||||
}
|
||||
|
||||
int MPEG::Header::bitrate() const
|
||||
{
|
||||
return d->bitrate;
|
||||
}
|
||||
|
||||
int MPEG::Header::sampleRate() const
|
||||
{
|
||||
return d->sampleRate;
|
||||
}
|
||||
|
||||
bool MPEG::Header::isPadded() const
|
||||
{
|
||||
return d->isPadded;
|
||||
}
|
||||
|
||||
MPEG::Header::ChannelMode MPEG::Header::channelMode() const
|
||||
{
|
||||
return d->channelMode;
|
||||
}
|
||||
|
||||
bool MPEG::Header::isCopyrighted() const
|
||||
{
|
||||
return d->isCopyrighted;
|
||||
}
|
||||
|
||||
bool MPEG::Header::isOriginal() const
|
||||
{
|
||||
return d->isOriginal;
|
||||
}
|
||||
|
||||
int MPEG::Header::frameLength() const
|
||||
{
|
||||
return d->frameLength;
|
||||
}
|
||||
|
||||
int MPEG::Header::samplesPerFrame() const
|
||||
{
|
||||
return d->samplesPerFrame;
|
||||
}
|
||||
|
||||
MPEG::Header &MPEG::Header::operator=(const Header &h)
|
||||
{
|
||||
if(&h == this)
|
||||
return *this;
|
||||
|
||||
if(d->deref())
|
||||
delete d;
|
||||
|
||||
d = h.d;
|
||||
d->ref();
|
||||
return *this;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void MPEG::Header::parse(File *file, long offset, bool checkLength)
|
||||
{
|
||||
file->seek(offset);
|
||||
const ByteVector data = file->readBlock(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)) {
|
||||
debug("MPEG::Header::parse() -- MPEG header did not match MPEG synch.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the MPEG version
|
||||
|
||||
const int versionBits = (static_cast<unsigned char>(data[1]) >> 3) & 0x03;
|
||||
|
||||
if(versionBits == 0)
|
||||
d->version = Version2_5;
|
||||
else if(versionBits == 2)
|
||||
d->version = Version2;
|
||||
else if(versionBits == 3)
|
||||
d->version = Version1;
|
||||
else
|
||||
return;
|
||||
|
||||
// Set the MPEG layer
|
||||
|
||||
const int layerBits = (static_cast<unsigned char>(data[1]) >> 1) & 0x03;
|
||||
|
||||
if(layerBits == 1)
|
||||
d->layer = 3;
|
||||
else if(layerBits == 2)
|
||||
d->layer = 2;
|
||||
else if(layerBits == 3)
|
||||
d->layer = 1;
|
||||
else
|
||||
return;
|
||||
|
||||
d->protectionEnabled = (static_cast<unsigned char>(data[1] & 0x01) == 0);
|
||||
|
||||
// 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 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;
|
||||
|
||||
// The bitrate index is encoded as the first 4 bits of the 3rd byte,
|
||||
// i.e. 1111xxxx
|
||||
|
||||
const int bitrateIndex = (static_cast<unsigned char>(data[2]) >> 4) & 0x0F;
|
||||
|
||||
d->bitrate = bitrates[versionIndex][layerIndex][bitrateIndex];
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
// The sample rate index is encoded as two bits in the 3nd byte, i.e. xxxx11xx
|
||||
|
||||
const int samplerateIndex = (static_cast<unsigned char>(data[2]) >> 2) & 0x03;
|
||||
|
||||
d->sampleRate = sampleRates[d->version][samplerateIndex];
|
||||
|
||||
if(d->sampleRate == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The channel mode is encoded as a 2 bit value at the end of the 3nd byte,
|
||||
// i.e. xxxxxx11
|
||||
|
||||
d->channelMode = static_cast<ChannelMode>((static_cast<unsigned char>(data[3]) >> 6) & 0x03);
|
||||
|
||||
// TODO: Add mode extension for completeness
|
||||
|
||||
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);
|
||||
|
||||
// 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
|
||||
};
|
||||
|
||||
d->samplesPerFrame = samplesPerFrame[layerIndex][versionIndex];
|
||||
|
||||
// Calculate the frame length
|
||||
|
||||
static const int paddingSize[3] = { 4, 1, 1 };
|
||||
|
||||
d->frameLength = d->samplesPerFrame * d->bitrate * 125 / d->sampleRate;
|
||||
|
||||
if(d->isPadded)
|
||||
d->frameLength += paddingSize[layerIndex];
|
||||
|
||||
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.
|
||||
|
||||
// The MPEG versions, layers and sample rates of the two frames should be
|
||||
// consistent. Otherwise, we assume that either or both of the frames are
|
||||
// broken.
|
||||
|
||||
file->seek(offset + d->frameLength);
|
||||
const ByteVector nextData = file->readBlock(4);
|
||||
|
||||
if(nextData.size() < 4)
|
||||
return;
|
||||
|
||||
const unsigned int HeaderMask = 0xfffe0c00;
|
||||
|
||||
const unsigned int header = data.toUInt(0, true) & HeaderMask;
|
||||
const unsigned int nextHeader = nextData.toUInt(0, true) & HeaderMask;
|
||||
|
||||
if(header != nextHeader)
|
||||
return;
|
||||
}
|
||||
|
||||
// Now that we're done parsing, set this to be a valid frame.
|
||||
|
||||
d->isValid = true;
|
||||
}
|
||||
178
3rdparty/taglib/mpeg/mpegheader.h
vendored
Normal file
178
3rdparty/taglib/mpeg/mpegheader.h
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_MPEGHEADER_H
|
||||
#define TAGLIB_MPEGHEADER_H
|
||||
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
class ByteVector;
|
||||
class File;
|
||||
|
||||
namespace MPEG {
|
||||
|
||||
//! 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:
|
||||
/*!
|
||||
* Parses an MPEG header based on \a data.
|
||||
*
|
||||
* \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);
|
||||
|
||||
/*!
|
||||
* Does a shallow copy of \a h.
|
||||
*/
|
||||
Header(const Header &h);
|
||||
|
||||
/*!
|
||||
* Destroys this Header instance.
|
||||
*/
|
||||
virtual ~Header();
|
||||
|
||||
/*!
|
||||
* Returns true if the frame is at least an appropriate size and has
|
||||
* legal values.
|
||||
*/
|
||||
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
|
||||
};
|
||||
|
||||
/*!
|
||||
* Returns the MPEG Version of the header.
|
||||
*/
|
||||
Version version() const;
|
||||
|
||||
/*!
|
||||
* Returns the layer version. This will be between the values 1-3.
|
||||
*/
|
||||
int layer() const;
|
||||
|
||||
/*!
|
||||
* Returns true if the MPEG protection bit is enabled.
|
||||
*/
|
||||
bool protectionEnabled() const;
|
||||
|
||||
/*!
|
||||
* Returns the bitrate encoded in the header.
|
||||
*/
|
||||
int bitrate() const;
|
||||
|
||||
/*!
|
||||
* Returns the sample rate in Hz.
|
||||
*/
|
||||
int sampleRate() const;
|
||||
|
||||
/*!
|
||||
* Returns true if the frame is padded.
|
||||
*/
|
||||
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
|
||||
};
|
||||
|
||||
/*!
|
||||
* Returns the channel mode for this frame.
|
||||
*/
|
||||
ChannelMode channelMode() const;
|
||||
|
||||
/*!
|
||||
* Returns true if the copyrighted bit is set.
|
||||
*/
|
||||
bool isCopyrighted() const;
|
||||
|
||||
/*!
|
||||
* Returns true if the "original" bit is set.
|
||||
*/
|
||||
bool isOriginal() const;
|
||||
|
||||
/*!
|
||||
* Returns the frame length in bytes.
|
||||
*/
|
||||
int frameLength() const;
|
||||
|
||||
/*!
|
||||
* Returns the number of frames per sample.
|
||||
*/
|
||||
int samplesPerFrame() const;
|
||||
|
||||
/*!
|
||||
* Makes a shallow copy of the header.
|
||||
*/
|
||||
Header &operator=(const Header &h);
|
||||
|
||||
private:
|
||||
void parse(File *file, long offset, bool checkLength);
|
||||
|
||||
class HeaderPrivate;
|
||||
HeaderPrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
220
3rdparty/taglib/mpeg/mpegproperties.cpp
vendored
Normal file
220
3rdparty/taglib/mpeg/mpegproperties.cpp
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tdebug.h>
|
||||
#include <tstring.h>
|
||||
|
||||
#include "mpegproperties.h"
|
||||
#include "mpegfile.h"
|
||||
#include "xingheader.h"
|
||||
#include "apetag.h"
|
||||
#include "apefooter.h"
|
||||
|
||||
using namespace 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) {}
|
||||
|
||||
~PropertiesPrivate()
|
||||
{
|
||||
delete xingHeader;
|
||||
}
|
||||
|
||||
XingHeader *xingHeader;
|
||||
int length;
|
||||
int bitrate;
|
||||
int sampleRate;
|
||||
int channels;
|
||||
int layer;
|
||||
Header::Version version;
|
||||
Header::ChannelMode channelMode;
|
||||
bool protectionEnabled;
|
||||
bool isCopyrighted;
|
||||
bool isOriginal;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MPEG::Properties::Properties(File *file, ReadStyle style) :
|
||||
AudioProperties(style),
|
||||
d(new PropertiesPrivate())
|
||||
{
|
||||
read(file);
|
||||
}
|
||||
|
||||
MPEG::Properties::~Properties()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
int MPEG::Properties::length() const
|
||||
{
|
||||
return lengthInSeconds();
|
||||
}
|
||||
|
||||
int MPEG::Properties::lengthInSeconds() const
|
||||
{
|
||||
return d->length / 1000;
|
||||
}
|
||||
|
||||
int MPEG::Properties::lengthInMilliseconds() const
|
||||
{
|
||||
return d->length;
|
||||
}
|
||||
|
||||
int MPEG::Properties::bitrate() const
|
||||
{
|
||||
return d->bitrate;
|
||||
}
|
||||
|
||||
int MPEG::Properties::sampleRate() const
|
||||
{
|
||||
return d->sampleRate;
|
||||
}
|
||||
|
||||
int MPEG::Properties::channels() const
|
||||
{
|
||||
return d->channels;
|
||||
}
|
||||
|
||||
const MPEG::XingHeader *MPEG::Properties::xingHeader() const
|
||||
{
|
||||
return d->xingHeader;
|
||||
}
|
||||
|
||||
MPEG::Header::Version MPEG::Properties::version() const
|
||||
{
|
||||
return d->version;
|
||||
}
|
||||
|
||||
int MPEG::Properties::layer() const
|
||||
{
|
||||
return d->layer;
|
||||
}
|
||||
|
||||
bool MPEG::Properties::protectionEnabled() const
|
||||
{
|
||||
return d->protectionEnabled;
|
||||
}
|
||||
|
||||
MPEG::Header::ChannelMode MPEG::Properties::channelMode() const
|
||||
{
|
||||
return d->channelMode;
|
||||
}
|
||||
|
||||
bool MPEG::Properties::isCopyrighted() const
|
||||
{
|
||||
return d->isCopyrighted;
|
||||
}
|
||||
|
||||
bool MPEG::Properties::isOriginal() const
|
||||
{
|
||||
return d->isOriginal;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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) {
|
||||
debug("MPEG::Properties::read() -- Could not find an MPEG frame in the stream.");
|
||||
return;
|
||||
}
|
||||
|
||||
const Header firstHeader(file, firstFrameOffset, false);
|
||||
|
||||
// Check for a VBR header that will help us in gathering information about a
|
||||
// VBR stream.
|
||||
|
||||
file->seek(firstFrameOffset);
|
||||
d->xingHeader = new XingHeader(file->readBlock(firstHeader.frameLength()));
|
||||
if(!d->xingHeader->isValid()) {
|
||||
delete d->xingHeader;
|
||||
d->xingHeader = 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->bitrate = static_cast<int>(d->xingHeader->totalSize() * 8.0 / length + 0.5);
|
||||
}
|
||||
else if(firstHeader.bitrate() > 0) {
|
||||
|
||||
// Since there was no valid VBR header found, we hope that we're in a constant
|
||||
// bitrate file.
|
||||
|
||||
// TODO: Make this more robust with audio property detection for VBR without a
|
||||
// Xing header.
|
||||
|
||||
d->bitrate = firstHeader.bitrate();
|
||||
|
||||
// Look for the last MPEG audio frame to calculate the stream length.
|
||||
|
||||
const long lastFrameOffset = file->lastFrameOffset();
|
||||
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)
|
||||
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->protectionEnabled = firstHeader.protectionEnabled();
|
||||
d->channelMode = firstHeader.channelMode();
|
||||
d->isCopyrighted = firstHeader.isCopyrighted();
|
||||
d->isOriginal = firstHeader.isOriginal();
|
||||
}
|
||||
152
3rdparty/taglib/mpeg/mpegproperties.h
vendored
Normal file
152
3rdparty/taglib/mpeg/mpegproperties.h
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_MPEGPROPERTIES_H
|
||||
#define TAGLIB_MPEGPROPERTIES_H
|
||||
|
||||
#include "taglib_export.h"
|
||||
#include "audioproperties.h"
|
||||
|
||||
#include "mpegheader.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace MPEG {
|
||||
|
||||
class File;
|
||||
class XingHeader;
|
||||
|
||||
//! 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:
|
||||
/*!
|
||||
* Create an instance of MPEG::Properties with the data read from the
|
||||
* MPEG::File \a file.
|
||||
*/
|
||||
Properties(File *file, ReadStyle style = Average);
|
||||
|
||||
/*!
|
||||
* Destroys this MPEG Properties instance.
|
||||
*/
|
||||
virtual ~Properties();
|
||||
|
||||
/*!
|
||||
* Returns the length of the file in seconds. The length is rounded down to
|
||||
* the nearest whole second.
|
||||
*
|
||||
* \note This method is just an alias of lengthInSeconds().
|
||||
*
|
||||
* \deprecated
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Returns the length of the file in milliseconds.
|
||||
*
|
||||
* \see lengthInSeconds()
|
||||
*/
|
||||
// BIC: make virtual
|
||||
int lengthInMilliseconds() const;
|
||||
|
||||
/*!
|
||||
* Returns the average bit rate of the file in kb/s.
|
||||
*/
|
||||
virtual int bitrate() const;
|
||||
|
||||
/*!
|
||||
* Returns the sample rate in Hz.
|
||||
*/
|
||||
virtual int sampleRate() const;
|
||||
|
||||
/*!
|
||||
* Returns the number of audio channels.
|
||||
*/
|
||||
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;
|
||||
|
||||
/*!
|
||||
* Returns the MPEG Version of the file.
|
||||
*/
|
||||
Header::Version version() const;
|
||||
|
||||
/*!
|
||||
* Returns the layer version. This will be between the values 1-3.
|
||||
*/
|
||||
int layer() const;
|
||||
|
||||
/*!
|
||||
* Returns true if the MPEG protection bit is enabled.
|
||||
*/
|
||||
bool protectionEnabled() const;
|
||||
|
||||
/*!
|
||||
* Returns the channel mode for this frame.
|
||||
*/
|
||||
Header::ChannelMode channelMode() const;
|
||||
|
||||
/*!
|
||||
* Returns true if the copyrighted bit is set.
|
||||
*/
|
||||
bool isCopyrighted() const;
|
||||
|
||||
/*!
|
||||
* Returns true if the "original" bit is set.
|
||||
*/
|
||||
bool isOriginal() const;
|
||||
|
||||
private:
|
||||
Properties(const Properties &);
|
||||
Properties &operator=(const Properties &);
|
||||
|
||||
void read(File *file);
|
||||
|
||||
class PropertiesPrivate;
|
||||
PropertiesPrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
63
3rdparty/taglib/mpeg/mpegutils.h
vendored
Normal file
63
3rdparty/taglib/mpeg/mpegutils.h
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2015 by Tsuda Kageyu
|
||||
email : tsuda.kageyu@gmail.com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_MPEGUTILS_H
|
||||
#define TAGLIB_MPEGUTILS_H
|
||||
|
||||
// THIS FILE IS NOT A PART OF THE TAGLIB API
|
||||
|
||||
#ifndef DO_NOT_DOCUMENT // tell Doxygen not to document this header
|
||||
|
||||
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.
|
||||
*
|
||||
* \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.
|
||||
|
||||
const unsigned char b1 = bytes[offset + 0];
|
||||
const unsigned char b2 = bytes[offset + 1];
|
||||
return (b1 == 0xFF && b2 != 0xFF && (b2 & 0xE0) == 0xE0);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
140
3rdparty/taglib/mpeg/xingheader.cpp
vendored
Normal file
140
3rdparty/taglib/mpeg/xingheader.cpp
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2003 by Ismael Orenstein
|
||||
email : orenstein@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tbytevector.h>
|
||||
#include <tstring.h>
|
||||
#include <tdebug.h>
|
||||
|
||||
#include "xingheader.h"
|
||||
#include "mpegfile.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class MPEG::XingHeader::XingHeaderPrivate
|
||||
{
|
||||
public:
|
||||
XingHeaderPrivate() :
|
||||
frames(0),
|
||||
size(0),
|
||||
type(MPEG::XingHeader::Invalid) {}
|
||||
|
||||
unsigned int frames;
|
||||
unsigned int size;
|
||||
|
||||
MPEG::XingHeader::HeaderType type;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MPEG::XingHeader::XingHeader(const ByteVector &data) :
|
||||
d(new XingHeaderPrivate())
|
||||
{
|
||||
parse(data);
|
||||
}
|
||||
|
||||
MPEG::XingHeader::~XingHeader()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool MPEG::XingHeader::isValid() const
|
||||
{
|
||||
return (d->type != Invalid && d->frames > 0 && d->size > 0);
|
||||
}
|
||||
|
||||
unsigned int MPEG::XingHeader::totalFrames() const
|
||||
{
|
||||
return d->frames;
|
||||
}
|
||||
|
||||
unsigned int MPEG::XingHeader::totalSize() const
|
||||
{
|
||||
return d->size;
|
||||
}
|
||||
|
||||
MPEG::XingHeader::HeaderType MPEG::XingHeader::type() const
|
||||
{
|
||||
return d->type;
|
||||
}
|
||||
|
||||
int MPEG::XingHeader::xingHeaderOffset(TagLib::MPEG::Header::Version /*v*/,
|
||||
TagLib::MPEG::Header::ChannelMode /*c*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void MPEG::XingHeader::parse(const ByteVector &data)
|
||||
{
|
||||
// Look for a Xing header.
|
||||
|
||||
long offset = data.find("Xing");
|
||||
if(offset < 0)
|
||||
offset = data.find("Info");
|
||||
|
||||
if(offset >= 0) {
|
||||
|
||||
// Xing header found.
|
||||
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
else {
|
||||
|
||||
// Xing header not found. Then look for a VBRI header.
|
||||
|
||||
offset = data.find("VBRI");
|
||||
|
||||
if(offset >= 0) {
|
||||
|
||||
// VBRI header found.
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
129
3rdparty/taglib/mpeg/xingheader.h
vendored
Normal file
129
3rdparty/taglib/mpeg/xingheader.h
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2003 by Ismael Orenstein
|
||||
email : orenstein@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_XINGHEADER_H
|
||||
#define TAGLIB_XINGHEADER_H
|
||||
|
||||
#include "mpegheader.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
class ByteVector;
|
||||
|
||||
namespace MPEG {
|
||||
|
||||
class File;
|
||||
|
||||
//! 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
|
||||
* implementation is only concerned with the total size of the stream (so
|
||||
* that we can calculate the total playing time and the average bitrate).
|
||||
* It uses <a href="http://home.pcisys.net/~melanson/codecs/mp3extensions.txt">
|
||||
* this text</a> and the XMMS sources as references.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT XingHeader
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* The type of the VBR header.
|
||||
*/
|
||||
enum HeaderType
|
||||
{
|
||||
/*!
|
||||
* Invalid header or no VBR header found.
|
||||
*/
|
||||
Invalid = 0,
|
||||
|
||||
/*!
|
||||
* Xing header.
|
||||
*/
|
||||
Xing = 1,
|
||||
|
||||
/*!
|
||||
* VBRI header.
|
||||
*/
|
||||
VBRI = 2,
|
||||
};
|
||||
|
||||
/*!
|
||||
* Parses an Xing/VBRI header based on \a data which contains the entire
|
||||
* first MPEG frame.
|
||||
*/
|
||||
XingHeader(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Destroy this XingHeader instance.
|
||||
*/
|
||||
virtual ~XingHeader();
|
||||
|
||||
/*!
|
||||
* Returns true if the data was parsed properly and if there is a valid
|
||||
* Xing/VBRI header present.
|
||||
*/
|
||||
bool isValid() const;
|
||||
|
||||
/*!
|
||||
* Returns the total number of frames.
|
||||
*/
|
||||
unsigned int totalFrames() const;
|
||||
|
||||
/*!
|
||||
* Returns the total size of stream in bytes.
|
||||
*/
|
||||
unsigned int totalSize() const;
|
||||
|
||||
/*!
|
||||
* Returns the type of the VBR header.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
static int xingHeaderOffset(TagLib::MPEG::Header::Version v,
|
||||
TagLib::MPEG::Header::ChannelMode c);
|
||||
|
||||
private:
|
||||
XingHeader(const XingHeader &);
|
||||
XingHeader &operator=(const XingHeader &);
|
||||
|
||||
void parse(const ByteVector &data);
|
||||
|
||||
class XingHeaderPrivate;
|
||||
XingHeaderPrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user