This commit was manufactured by cvs2svn to accommodate

a server-side copy/move.


git-svn-id: svn://anonsvn.kde.org/home/kde/trunk/kdesupport/taglib@288617 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
This commit is contained in:
Scott Wheeler
2004-02-17 02:11:05 +00:00
commit 7fe6647435
97 changed files with 17567 additions and 0 deletions

23
mpeg/id3v2/Makefile.am Normal file
View File

@ -0,0 +1,23 @@
SUBDIRS = frames
INCLUDES = \
-I$(top_srcdir)/taglib \
-I$(top_srcdir)/taglib/toolkit \
-I$(top_srcdir)/taglib/mpeg \
-I$(top_srcdir)/taglib/mpeg/id3v1 \
$(all_includes)
noinst_LTLIBRARIES = libid3v2.la
libid3v2_la_SOURCES = \
id3v2framefactory.cpp id3v2synchdata.cpp id3v2tag.cpp \
id3v2header.cpp id3v2frame.cpp id3v2footer.cpp \
id3v2extendedheader.cpp
taglib_include_HEADERS = \
id3v2extendedheader.h id3v2frame.h id3v2header.h \
id3v2synchdata.h id3v2footer.h id3v2framefactory.h id3v2tag.h
taglib_includedir = $(includedir)/taglib
libid3v2_la_LIBADD = ./frames/libframes.la
EXTRA_DIST = $(libid3v2_la_SOURCES) $(taglib_include_HEADERS) id3v2.4.0-frames.txt id3v2.4.0-structure.txt

View File

@ -0,0 +1,13 @@
INCLUDES = \
-I$(top_srcdir)/taglib/toolkit \
-I$(top_srcdir)/taglib/mpeg/id3v2 \
$(all_includes)
noinst_LTLIBRARIES = libframes.la
libframes_la_SOURCES = unknownframe.cpp textidentificationframe.cpp commentsframe.cpp
taglib_include_HEADERS = unknownframe.h textidentificationframe.h commentsframe.h
taglib_includedir = $(includedir)/taglib
EXTRA_DIST = $(libframes_la_SOURCES) $(taglib_include_HEADERS)

View File

@ -0,0 +1,152 @@
/***************************************************************************
copyright : (C) 2002, 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
* USA *
***************************************************************************/
#include <tbytevectorlist.h>
#include <tdebug.h>
#include "commentsframe.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();
parseFields(data.mid(Header::size(), size()));
}
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;
}
////////////////////////////////////////////////////////////////////////////////
// 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);
if(l.size() == 2) {
d->description = String(l.front(), d->textEncoding);
d->text = String(l.back(), d->textEncoding);
}
}
ByteVector CommentsFrame::renderFields() const
{
ByteVector v;
v.append(char(d->textEncoding));
v.append(d->language);
v.append(d->description.data(d->textEncoding));
v.append(textDelimiter(d->textEncoding));
v.append(d->text.data(d->textEncoding));
return v;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
CommentsFrame::CommentsFrame(const ByteVector &data, Header *h) : Frame(h)
{
d = new CommentsFramePrivate();
parseFields(data.mid(Header::size(), size()));
}

View File

@ -0,0 +1,154 @@
/***************************************************************************
copyright : (C) 2002, 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
* USA *
***************************************************************************/
#ifndef TAGLIB_COMMENTSFRAME_H
#define TAGLIB_COMMENTSFRAME_H
#include <id3v2frame.h>
namespace TagLib {
namespace ID3v2 {
//! An implementation of ID3v2 comments
/*!
* This implements the ID3v2 comment format. An ID3v2 comment concists of
* a language encoding, a description and a single text field.
*/
class 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 decription()
*/
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);
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

View File

@ -0,0 +1,150 @@
/***************************************************************************
copyright : (C) 2002, 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
* USA *
***************************************************************************/
#include <tbytevectorlist.h>
#include "textidentificationframe.h"
using namespace TagLib;
using namespace ID3v2;
class TextIdentificationFrame::TextIdentificationFramePrivate
{
public:
TextIdentificationFramePrivate() : textEncoding(String::Latin1) {}
String::Type textEncoding;
StringList fieldList;
};
////////////////////////////////////////////////////////////////////////////////
// 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()
{
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;
}
////////////////////////////////////////////////////////////////////////////////
// protected members
////////////////////////////////////////////////////////////////////////////////
void TextIdentificationFrame::parseFields(const ByteVector &data)
{
// 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;
ByteVectorList l = ByteVectorList::split(data.mid(1), 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::Iterator it = l.begin(); it != l.end(); it++) {
String s(*it, d->textEncoding);
d->fieldList.append(s);
}
}
ByteVector TextIdentificationFrame::renderFields() const
{
ByteVector v;
if(d->fieldList.size() > 0) {
v.append(char(d->textEncoding));
for(StringList::Iterator 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(d->textEncoding));
v.append((*it).data(d->textEncoding));
}
}
return v;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data, Header *h) : Frame(h)
{
d = new TextIdentificationFramePrivate;
parseFields(data.mid(Header::size(), size()));
}

View File

@ -0,0 +1,179 @@
/***************************************************************************
copyright : (C) 2002, 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
* USA *
***************************************************************************/
#ifndef TAGLIB_TEXTIDENTIFICATIONFRAME_H
#define TAGLIB_TEXTIDENTIFICATIONFRAME_H
#include <tstringlist.h>
#include <id3v2frame.h>
namespace TagLib {
namespace ID3v2 {
//! 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.
*/
class 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.
*/
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);
/*!
* 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.
*
* \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 a list of the strings in this frame.
*/
StringList fieldList() const;
protected:
// Reimplementations.
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
private:
/*!
* The constructor used by the FrameFactory.
*/
TextIdentificationFrame(const ByteVector &data, Header *h);
TextIdentificationFrame(const TextIdentificationFrame &);
TextIdentificationFrame &operator=(const TextIdentificationFrame &);
class TextIdentificationFramePrivate;
TextIdentificationFramePrivate *d;
};
}
}
#endif

View File

@ -0,0 +1,80 @@
/***************************************************************************
copyright : (C) 2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
* USA *
***************************************************************************/
#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::null;
}
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(data.mid(Header::size(), size()));
}

View File

@ -0,0 +1,74 @@
/***************************************************************************
copyright : (C) 2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
* USA *
***************************************************************************/
#ifndef TAGLIB_UNKNOWNFRAME_H
#define TAGLIB_UNKNOWNFRAME_H
#include <id3v2frame.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 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

File diff suppressed because it is too large Load Diff

View 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<73>gen 246 C. 30
SE-584 34 Link<6E>ping
Sweden
Email: nilsson@id3.org

View File

@ -0,0 +1,67 @@
/***************************************************************************
copyright : (C) 2002, 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
* USA *
***************************************************************************/
#include "id3v2extendedheader.h"
#include "id3v2synchdata.h"
using namespace TagLib;
using namespace ID3v2;
class ExtendedHeader::ExtendedHeaderPrivate
{
public:
ExtendedHeaderPrivate() : size(0) {}
uint size;
};
////////////////////////////////////////////////////////////////////////////////
// public methods
////////////////////////////////////////////////////////////////////////////////
ExtendedHeader::ExtendedHeader()
{
d = new ExtendedHeaderPrivate();
}
ExtendedHeader::~ExtendedHeader()
{
delete d;
}
TagLib::uint 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")
}

View File

@ -0,0 +1,88 @@
/***************************************************************************
copyright : (C) 2002, 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
* USA *
***************************************************************************/
#ifndef TAGLIB_ID3V2EXTENDEDHEADER_H
#define TAGLIB_ID3V2EXTENDEDHEADER_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 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.
*/
uint 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

View File

@ -0,0 +1,56 @@
/***************************************************************************
copyright : (C) 2002, 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
* USA *
***************************************************************************/
#include "id3v2footer.h"
#include "id3v2header.h"
using namespace TagLib;
using namespace ID3v2;
class Footer::FooterPrivate
{
public:
static const uint size = 10;
};
Footer::Footer()
{
}
Footer::~Footer()
{
}
const unsigned int Footer::size()
{
return FooterPrivate::size;
}
ByteVector Footer::render(const Header *header) const
{
ByteVector headerData = header->render();
headerData[0] = '3';
headerData[1] = 'D';
headerData[2] = 'I';
return headerData;
}

77
mpeg/id3v2/id3v2footer.h Normal file
View File

@ -0,0 +1,77 @@
/***************************************************************************
copyright : (C) 2002, 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
* USA *
***************************************************************************/
#ifndef TAGLIB_ID3V2FOOTER_H
#define TAGLIB_ID3V2FOOTER_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 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 const 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

241
mpeg/id3v2/id3v2frame.cpp Normal file
View File

@ -0,0 +1,241 @@
/***************************************************************************
copyright : (C) 2002, 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
* USA *
***************************************************************************/
#include <tdebug.h>
#include "id3v2frame.h"
#include "id3v2synchdata.h"
using namespace TagLib;
using namespace ID3v2;
class Frame::FramePrivate
{
public:
FramePrivate() {
header = 0;
}
~FramePrivate() {
delete header;
}
Frame::Header *header;
};
////////////////////////////////////////////////////////////////////////////////
// static methods
////////////////////////////////////////////////////////////////////////////////
TagLib::uint Frame::headerSize()
{
return Header::size();
}
ByteVector Frame::textDelimiter(String::Type t)
{
ByteVector d = char(0);
if(t == String::UTF16 || t == String::UTF16BE)
d.append(char(0));
return d;
}
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
Frame::~Frame()
{
delete d;
}
ByteVector Frame::frameID() const
{
if(d->header)
return d->header->frameID();
else
return ByteVector::null;
}
TagLib::uint 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);
// size() is the lenght of the field data
parseFields(data.mid(Header::size(), size()));
}
////////////////////////////////////////////////////////////////////////////////
// Frame::Header class
////////////////////////////////////////////////////////////////////////////////
class Frame::Header::HeaderPrivate
{
public:
HeaderPrivate() : frameSize(0) {}
ByteVector frameID;
uint frameSize;
static const unsigned int size = 10;
};
////////////////////////////////////////////////////////////////////////////////
// static members (Frame::Header)
////////////////////////////////////////////////////////////////////////////////
TagLib::uint Frame::Header::size()
{
return HeaderPrivate::size;
}
////////////////////////////////////////////////////////////////////////////////
// public members (Frame::Header)
////////////////////////////////////////////////////////////////////////////////
Frame::Header::Header(const ByteVector &data, bool synchSafeInts)
{
d = new HeaderPrivate;
setData(data, synchSafeInts);
}
Frame::Header::~Header()
{
delete d;
}
void Frame::Header::setData(const ByteVector &data, bool synchSafeInts)
{
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)
if(synchSafeInts)
d->frameSize = SynchData::toUInt(data.mid(4, 4));
else
d->frameSize = data.mid(4, 4).toUInt();
// read flags
// ...
}
ByteVector Frame::Header::frameID() const
{
return d->frameID;
}
void Frame::Header::setFrameID(const ByteVector &id)
{
d->frameID = id.mid(0, 4);
}
TagLib::uint Frame::Header::frameSize() const
{
return d->frameSize;
}
void Frame::Header::setFrameSize(uint size)
{
d->frameSize = size;
}
ByteVector Frame::Header::render() const
{
ByteVector flags(2, char(0)); // just blank for the moment
ByteVector v = d->frameID + SynchData::fromUInt(d->frameSize) + flags;
return v;
}

252
mpeg/id3v2/id3v2frame.h Normal file
View File

@ -0,0 +1,252 @@
/***************************************************************************
copyright : (C) 2002, 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
* USA *
***************************************************************************/
#ifndef TAGLIB_ID3V2FRAME_H
#define TAGLIB_ID3V2FRAME_H
#include <tstring.h>
#include <tbytevector.h>
namespace TagLib {
namespace ID3v2 {
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 Frame
{
friend class FrameFactory;
public:
/*!
* 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.
*/
uint size() const;
/*!
* Returns the size of the frame header
*/
static uint headerSize();
/*!
* 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);
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 constain 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;
private:
Frame(const Frame &);
Frame &operator=(const Frame &);
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 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.
*/
explicit Header(const ByteVector &data, bool synchSafeInts = true);
/*!
* Destroys this Header instance.
*/
virtual ~Header();
/*!
* Sets the data for the Header.
*/
void setData(const ByteVector &data, bool synchSafeInts = true);
/*!
* 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 explicity via setFrameSize().
*/
uint frameSize() const;
/*!
* Sets the size of the frame data portion.
*/
void setFrameSize(uint size);
/*!
* Returns the size of the frame header in bytes. Currently this is
* always 10.
*/
static uint size();
/*!
* Render the Header back to binary format in a ByteVector.
*/
ByteVector render() const;
private:
Header(const Header &);
Header &operator=(const Header &);
class HeaderPrivate;
HeaderPrivate *d;
};
}
}
#endif

View File

@ -0,0 +1,169 @@
/***************************************************************************
copyright : (C) 2002, 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
* USA *
***************************************************************************/
#include <tdebug.h>
#include "id3v2framefactory.h"
#include "frames/unknownframe.h"
#include "frames/textidentificationframe.h"
#include "frames/commentsframe.h"
using namespace TagLib;
using namespace ID3v2;
class FrameFactory::FrameFactoryPrivate
{
public:
FrameFactoryPrivate() :
defaultEncoding(String::Latin1),
useDefaultEncoding(false) {}
String::Type defaultEncoding;
bool useDefaultEncoding;
};
FrameFactory *FrameFactory::factory = 0;
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
FrameFactory *FrameFactory::instance()
{
if(!factory)
factory = new FrameFactory;
return factory;
}
Frame *FrameFactory::createFrame(const ByteVector &data, bool synchSafeInts) const
{
Frame::Header *header = new Frame::Header(data, synchSafeInts);
TagLib::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() == 4 || header->frameSize() <= 0)
return 0;
for(ByteVector::ConstIterator it = frameID.begin(); it != frameID.end(); it++) {
if( (*it < 'A' || *it > 'Z') && (*it < '1' || *it > '9') ) {
delete header;
return 0;
}
}
if(!updateFrame(header)) {
delete header;
return 0;
}
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)
if(frameID.startsWith("T") && frameID != "TXXX") {
TextIdentificationFrame *f = new TextIdentificationFrame(data, header);
if(d->useDefaultEncoding)
f->setTextEncoding(d->defaultEncoding);
return f;
}
// Comments (frames 4.10)
if(frameID == "COMM") {
CommentsFrame *f = new CommentsFrame(data, header);
if(d->useDefaultEncoding)
f->setTextEncoding(d->defaultEncoding);
return f;
}
return new UnknownFrame(data, header);
}
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;
}
bool FrameFactory::updateFrame(Frame::Header *header) const
{
TagLib::ByteVector frameID = header->frameID();
if(frameID == "EQUA" ||
frameID == "RVAD" ||
frameID == "TIME" ||
frameID == "TRDA" ||
frameID == "TSIZ")
{
debug("ID3v2.4 no longer supports the frame type " + String(frameID) +
". It will be discarded from the tag.");
return false;
}
convertFrame("TDAT", "TRDC", header);
convertFrame("TORY", "TDOR", header);
convertFrame("TYER", "TRDC", header);
return true;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void FrameFactory::convertFrame(const ByteVector &from, const ByteVector &to,
Frame::Header *header) const
{
if(header->frameID() != from)
return;
// debug("ID3v2.4 no longer supports the frame type " + String(from) + " It has" +
// "been converted to the type " + String(to) + ".");
header->setFrameID(to);
}

View File

@ -0,0 +1,129 @@
/***************************************************************************
copyright : (C) 2002, 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
* USA *
***************************************************************************/
#ifndef TAGLIB_ID3V2FRAMEFACTORY_H
#define TAGLIB_ID3V2FRAMEFACTORY_H
#include <tbytevector.h>
#include "id3v2frame.h"
namespace TagLib {
namespace ID3v2 {
//! A factory for creating ID3v2 frames
/*!
* 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 or with
* MPEG::File::setID3v2FrameFactory() 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>).
*/
class 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.
*/
Frame *createFrame(const ByteVector &data, bool synchSafeInts = true) 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 explitly 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.
*
* \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. In most cases this will never be called (as
* is typical of singletons).
*/
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 &);
/*!
* This method is used internally to convert a frame from ID \a from to ID
* \a to. If the frame matches the \a from pattern and converts the frame
* ID in the \a header or simply does nothing if the frame ID does not match.
*/
void convertFrame(const ByteVector &from, const ByteVector &to,
Frame::Header *header) const;
static FrameFactory *factory;
class FrameFactoryPrivate;
FrameFactoryPrivate *d;
};
}
}
#endif

227
mpeg/id3v2/id3v2header.cpp Normal file
View File

@ -0,0 +1,227 @@
/***************************************************************************
copyright : (C) 2002, 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
* USA *
***************************************************************************/
#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(0),
revisionNumber(0),
unsynchronisation(false),
extendedHeader(false),
experimentalIndicator(false),
footerPresent(false),
tagSize(0) {}
~HeaderPrivate() {}
uint majorVersion;
uint revisionNumber;
bool unsynchronisation;
bool extendedHeader;
bool experimentalIndicator;
bool footerPresent;
uint tagSize;
static const uint size = 10;
};
////////////////////////////////////////////////////////////////////////////////
// static members
////////////////////////////////////////////////////////////////////////////////
TagLib::uint Header::size()
{
return HeaderPrivate::size;
}
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;
}
TagLib::uint Header::majorVersion() const
{
return d->majorVersion;
}
TagLib::uint 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;
}
TagLib::uint Header::tagSize() const
{
return d->tagSize;
}
TagLib::uint Header::completeTagSize() const
{
if(d->footerPresent)
return d->tagSize + d->size + Footer::size();
else
return d->tagSize + d->size;
}
void Header::setTagSize(uint 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(4));
v.append(char(0));
// 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::Iterator it = sizeData.begin(); it != sizeData.end(); it++) {
if(uchar(*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")
}

159
mpeg/id3v2/id3v2header.h Normal file
View File

@ -0,0 +1,159 @@
/***************************************************************************
copyright : (C) 2002, 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
* USA *
***************************************************************************/
#ifndef TAGLIB_ID3V2HEADER_H
#define TAGLIB_ID3V2HEADER_H
#include <tbytevector.h>
namespace TagLib {
namespace ID3v2 {
//! An implementation of ID3v2 headers
/*!
* This class implements ID3v2 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 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 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.)
*/
uint majorVersion() const;
/*!
* Returns the revision number. (Note: This is the 0, not the 4 in
* ID3v2.4.0. The 2 is implied.)
*/
uint 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()
*/
uint tagSize() const;
/*!
* Returns the tag size, including the header and, if present, the footer
* size.
*
* \see tagSize()
*/
uint completeTagSize() const;
/*!
* Set the tag size to \a s.
* \see tagSize()
*/
void setTagSize(uint s);
/*!
* Returns the size of the header. Presently this is always 10 bytes.
*/
static uint 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 extended header. 10 bytes,
* starting from \a data will be 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

View File

@ -0,0 +1,48 @@
/***************************************************************************
copyright : (C) 2002, 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
* USA *
***************************************************************************/
#include <iostream>
#include "id3v2synchdata.h"
using namespace TagLib;
using namespace ID3v2;
TagLib::uint SynchData::toUInt(const ByteVector &data)
{
uint sum = 0;
int last = data.size() > 4 ? 3 : data.size() - 1;
for(int i = 0; i <= last; i++)
sum |= (data[i] & 0x7f) << ((last - i) * 7);
return sum;
}
ByteVector SynchData::fromUInt(uint value)
{
ByteVector v(4, 0);
for(int i = 0; i < 4; i++)
v[i] = uchar(value >> ((3 - i) * 7) & 0x7f);
return v;
}

View File

@ -0,0 +1,61 @@
/***************************************************************************
copyright : (C) 2002, 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
* USA *
***************************************************************************/
#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.
*/
uint toUInt(const ByteVector &data);
/*!
* Returns a 4 byte (32 bit) synchsafe integer based on \a value.
*/
ByteVector fromUInt(uint value);
}
}
}
#endif

417
mpeg/id3v2/id3v2tag.cpp Normal file
View File

@ -0,0 +1,417 @@
/***************************************************************************
copyright : (C) 2002, 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
* USA *
***************************************************************************/
#include <tfile.h>
#include <tdebug.h>
#include "id3v2tag.h"
#include "id3v2header.h"
#include "id3v2extendedheader.h"
#include "id3v2footer.h"
#include "id3v1genres.h"
#include "frames/textidentificationframe.h"
#include "frames/commentsframe.h"
using namespace TagLib;
using namespace ID3v2;
class ID3v2::Tag::TagPrivate
{
public:
TagPrivate() : file(0), tagOffset(-1), extendedHeader(0), footer(0), paddingSize(0)
{
frameList.setAutoDelete(true);
}
~TagPrivate()
{
delete extendedHeader;
delete footer;
}
File *file;
long tagOffset;
const FrameFactory *factory;
Header header;
ExtendedHeader *extendedHeader;
Footer *footer;
int paddingSize;
FrameListMap frameListMap;
FrameList frameList;
};
////////////////////////////////////////////////////////////////////////////////
// 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->file = file;
d->tagOffset = tagOffset;
d->factory = factory;
read();
}
ID3v2::Tag::~Tag()
{
delete d;
}
String ID3v2::Tag::title() const
{
if(!d->frameListMap["TIT2"].isEmpty())
return d->frameListMap["TIT2"].front()->toString();
return String::null;
}
String ID3v2::Tag::artist() const
{
if(!d->frameListMap["TPE1"].isEmpty())
return d->frameListMap["TPE1"].front()->toString();
return String::null;
}
String ID3v2::Tag::album() const
{
if(!d->frameListMap["TALB"].isEmpty())
return d->frameListMap["TALB"].front()->toString();
return String::null;
}
String ID3v2::Tag::comment() const
{
if(!d->frameListMap["COMM"].isEmpty())
return d->frameListMap["COMM"].front()->toString();
return String::null;
}
String ID3v2::Tag::genre() const
{
if(!d->frameListMap["TCON"].isEmpty()) {
String s = d->frameListMap["TCON"].front()->toString();
// ID3v2 "content type" can contain a ID3v1 genre number in parenthesis at
// the beginning of the field. If this is all that the field contains, do a
// translation from that number to the name and return that. If there is a
// string folloing the ID3v1 genre number, that is considered to be
// authoritative and we return that instead. Or finally, the field may
// simply be free text, in which case we just return the value.
int closing = s.find(")");
if(s.substr(0, 1) == "(" && closing > 0) {
if(closing == int(s.size() - 1))
return ID3v1::genre(s.substr(1, s.size() - 2).toInt());
else
return s.substr(closing + 1);
}
return s;
}
return String::null;
}
TagLib::uint ID3v2::Tag::year() const
{
if(!d->frameListMap["TRDC"].isEmpty())
return d->frameListMap["TRDC"].front()->toString().substr(0, 4).toInt();
return 0;
}
TagLib::uint 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;
}
int index = ID3v1::genreIndex(s);
if(index != 255)
setTextFrame("TCON", "(" + String::number(index) + ")");
else
setTextFrame("TCON", s);
}
void ID3v2::Tag::setYear(uint i)
{
if(i <= 0) {
removeFrames("TRDC");
return;
}
setTextFrame("TRDC", String::number(i));
}
void ID3v2::Tag::setTrack(uint 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;
}
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 *it;
}
void ID3v2::Tag::removeFrames(const ByteVector &id)
{
FrameList l = d->frameListMap[id];
for(FrameList::Iterator it = l.begin(); it != l.end(); ++it)
removeFrame(*it, true);
}
ByteVector ID3v2::Tag::render() 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.
ByteVector tagData;
// TODO: Render the extended header.
// Loop through the frames rendering them and adding them to the tagData.
for(FrameList::Iterator it = d->frameList.begin(); it != d->frameList.end(); it++)
tagData.append((*it)->render());
// Compute the amount of padding, and append that to tagData.
uint paddingSize = 0;
uint originalSize = d->header.tagSize();
if(tagData.size() < originalSize)
paddingSize = originalSize - tagData.size();
else
paddingSize = 1024;
tagData.append(ByteVector(paddingSize, char(0)));
// Set the tag size.
d->header.setTagSize(tagData.size());
// TODO: This should eventually include d->footer->render().
return d->header.render() + tagData;
}
////////////////////////////////////////////////////////////////////////////////
// protected members
////////////////////////////////////////////////////////////////////////////////
void ID3v2::Tag::read()
{
if(d->file && d->file->isOpen()) {
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)
return;
parse(d->file->readBlock(d->header.tagSize()));
}
}
void ID3v2::Tag::parse(const ByteVector &data)
{
uint frameDataOffset = 0;
uint 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()) {
frameDataOffset += 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
uint frameDataPosition = 0;
// Make sure that there is at least enough room in the remaining frame data for
// a frame header.
while(frameDataPosition < frameDataLength - Frame::headerSize()) {
// 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.");
d->paddingSize = frameDataLength - frameDataPosition;
return;
}
bool synchSafeInts = d->header.majorVersion() >= 4;
Frame *frame = d->factory->createFrame(data.mid(frameDataOffset + frameDataPosition),
synchSafeInts);
if(!frame)
return;
// Checks to make sure that frame parsed correctly.
if(frame->size() <= 0) {
delete frame;
return;
}
frameDataPosition += frame->size() + Frame::headerSize();
addFrame(frame);
}
}
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);
}
}

243
mpeg/id3v2/id3v2tag.h Normal file
View File

@ -0,0 +1,243 @@
/***************************************************************************
copyright : (C) 2002, 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
* USA *
***************************************************************************/
#ifndef TAGLIB_ID3V2TAG_H
#define TAGLIB_ID3V2TAG_H
#include <tag.h>
#include <tbytevector.h>
#include <tstring.h>
#include <tlist.h>
#include <tmap.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;
//! 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() corespond 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 instace. 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 distrubuted 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 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 incorperated 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 uint year() const;
virtual uint 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(uint i);
virtual void setTrack(uint 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 pointer to the frame list map. This is an FrameListMap of
* all of the frames in the tag.
*
* \warning You should not modify this data structure directly, instead
* use addFrame() and removeFrame().
*/
const FrameListMap &frameListMap() const;
/*!
* Returns a pointer to the frame list. This is an FrameList of all of
* the frames in the tag in the order that they were parsed.
*
* \warning You should not modify this data structure directly, instead
* use addFrame() and removeFrame().
*/
const FrameList &frameList() const;
/*!
* Add a frame to the tag. At this point the tag takes ownership of
* the frame and will handle freeing its memory.
*/
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.
*/
void removeFrame(Frame *frame, bool del = true);
/*!
* Remove all frames of type \a id from the tag and free their memory.
*/
void removeFrames(const ByteVector &id);
/*!
* Render the tag back to binary data, suitable to be written to disk.
*/
ByteVector render() const;
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);
private:
Tag(const Tag &);
Tag &operator=(const Tag &);
class TagPrivate;
TagPrivate *d;
};
}
}
#endif