mirror of
https://github.com/taglib/taglib.git
synced 2026-06-13 01:39:17 -04:00
ID3 interface complete; vorbis done; wav done
This commit is contained in:
@@ -109,7 +109,7 @@ void CommentsFrame::setTextEncoding(String::Type encoding)
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
PropertyMap CommentsFrame::asDescription() const
|
||||
PropertyMap CommentsFrame::asProperties() const
|
||||
{
|
||||
String key = PropertyMap::prepareKey(description());
|
||||
PropertyMap map;
|
||||
@@ -118,7 +118,7 @@ PropertyMap CommentsFrame::asDescription() const
|
||||
if(key.isNull())
|
||||
map.unsupportedData().append(L"COMM/" + description());
|
||||
else
|
||||
map.insert(key, text());
|
||||
map.insert("COMMENT:" + key, text());
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
@@ -137,15 +137,15 @@ namespace TagLib {
|
||||
void setTextEncoding(String::Type encoding);
|
||||
|
||||
/*!
|
||||
* Parses this frame as PropertyMap.
|
||||
* - description() will be used as key
|
||||
* - if description() is empty, the key will be "COMMENT"
|
||||
* Parses this frame as PropertyMap with a single key.
|
||||
* - if description() is empty or "COMMENT", the key will be "COMMENT"
|
||||
* - if description() is not a valid PropertyMap key, the frame will be
|
||||
* marked unsupported by an entry "COMM/<description>" in the unsupportedData()
|
||||
* attribute of the returned map.
|
||||
* - otherwise, the key will be "COMMENT:<description>"
|
||||
* - The single value will be the frame's text().
|
||||
*/
|
||||
PropertyMap asDescription() const;
|
||||
PropertyMap asProperties() const;
|
||||
|
||||
/*!
|
||||
* Comments each have a unique description. This searches for a comment
|
||||
|
||||
@@ -59,7 +59,7 @@ TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data) :
|
||||
|
||||
TextIdentificationFrame *TextIdentificationFrame::createTIPLFrame(const PropertyMap &properties) // static
|
||||
{
|
||||
TextIdentificationFrame* frame = TextIdentificationFrame("TIPL");
|
||||
TextIdentificationFrame *frame = TextIdentificationFrame("TIPL");
|
||||
StringList l;
|
||||
for(PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it){
|
||||
l.append(it->first);
|
||||
@@ -68,6 +68,21 @@ TextIdentificationFrame *TextIdentificationFrame::createTIPLFrame(const Property
|
||||
frame->setText(l);
|
||||
return frame;
|
||||
}
|
||||
|
||||
TextIdentificationFrame *TextIdentificationFrame::createTMCLFrame(const PropertyMap &properties) // static
|
||||
{
|
||||
TextIdentificationFrame *frame = TextIdentificationFrame("TMCL");
|
||||
StringList l;
|
||||
for(PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it){
|
||||
if(!it->first.startsWith(instrumentPrefix)) // should not happen
|
||||
continue;
|
||||
l.append(it->first.substr(instrumentPrefix.size()));
|
||||
l.append(it->second.toString(","));
|
||||
}
|
||||
frame->setText(l);
|
||||
return frame;
|
||||
}
|
||||
|
||||
TextIdentificationFrame::~TextIdentificationFrame()
|
||||
{
|
||||
delete d;
|
||||
|
||||
@@ -131,6 +131,13 @@ namespace TagLib {
|
||||
*/
|
||||
static TextIdentificationFrame *createTIPLFrame(const PropertyMap &properties);
|
||||
|
||||
/*!
|
||||
* This is a special factory method to create a TMCL (musician credits list)
|
||||
* frame from the given \a properties. Will parse key=[list of values] data
|
||||
* into the TMCL format as specified in the ID3 standard, where key should be
|
||||
* of the form instrumentPrefix:instrument.
|
||||
*/
|
||||
static TextIdentificationFrame *createTMCLFrame(const PropertyMap &properties);
|
||||
/*!
|
||||
* Destroys this TextIdentificationFrame instance.
|
||||
*/
|
||||
@@ -186,6 +193,7 @@ namespace TagLib {
|
||||
* to the corresponding key used in a TIPL ID3 frame to describe that role.
|
||||
*/
|
||||
static const KeyConversionMap &involvedPeopleMap();
|
||||
|
||||
PropertyMap asProperties() const;
|
||||
|
||||
protected:
|
||||
@@ -243,6 +251,12 @@ namespace TagLib {
|
||||
*/
|
||||
explicit UserTextIdentificationFrame(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Creates a user defined text identification frame with the given \a description
|
||||
* and \a text.
|
||||
*/
|
||||
UserTextIdentificationFrame(const String &description, const StringList &values, String::Type encoding = String::Latin1);
|
||||
|
||||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
|
||||
@@ -113,8 +113,14 @@ void UnsynchronizedLyricsFrame::setTextEncoding(String::Type encoding)
|
||||
|
||||
PropertyMap UnsynchronizedLyricsFrame::asProperties() const
|
||||
{
|
||||
String key = PropertyMap::prepareKey(description());
|
||||
PropertyMap map;
|
||||
map.insert("LYRICS", text());
|
||||
if(key.isEmpty())
|
||||
key = "LYRICS";
|
||||
if(key.isNull())
|
||||
map.unsupportedData().append(L"USLT/" + description());
|
||||
else
|
||||
map.insert("LYRICS:" + key, text());
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
@@ -139,6 +139,17 @@ namespace TagLib {
|
||||
* Parses this frame as PropertyMap. The returned map will contain a single key
|
||||
* "LYRICS" with the text() as single value.
|
||||
*/
|
||||
/*!
|
||||
* Parses this frame as PropertyMap with a single key.
|
||||
* - if description() is empty or "LYRICS", the key will be "LYRICS"
|
||||
* - if description() is not a valid PropertyMap key, the frame will be
|
||||
* marked unsupported by an entry "USLT/<description>" in the unsupportedData()
|
||||
* attribute of the returned map.
|
||||
* - otherwise, the key will be "LYRICS:<description>"
|
||||
* - The single value will be the frame's text().
|
||||
* Note that currently the language() field is not supported by the PropertyMap
|
||||
* interface.
|
||||
*/
|
||||
PropertyMap asProperties() const;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -162,7 +162,7 @@ PropertyMap UserUrlLinkFrame::asProperties() const
|
||||
if(key.isNull())
|
||||
map.unsupportedData().append(L"WXXX/" + description());
|
||||
else
|
||||
map.insert(key, url());
|
||||
map.insert("URL:" + key, url());
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
@@ -96,10 +96,54 @@ ByteVector Frame::textDelimiter(String::Type t)
|
||||
return d;
|
||||
}
|
||||
|
||||
String TextIdentificationFrame::instrumentPrefix("PERFORMER:");
|
||||
String TextIdentificationFrame::commentPrefix("COMMENT:");
|
||||
String TextIdentificationFrame::urlPrefix("URL:");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Frame *Frame::createTextualFrame(const String &key, const StringList &values) //static
|
||||
{
|
||||
// check if the key is contained in the key<=>frameID mapping
|
||||
ByteVector frameID = keyToFrameID(key);
|
||||
if(!frameID.isNull()) {
|
||||
if(frameID[0] == 'T'){ // text frame
|
||||
TextIdentificationFrame* frame = TextIdentificationFrame(frameID, String::UTF8);
|
||||
frame->setText(values);
|
||||
return frame;
|
||||
} else if(values.size() == 1){ // URL frame (not WXXX); support only one value
|
||||
UrlLinkFrame* frame = UrlLinkFrame(frameID);
|
||||
frame->setUrl(values.front());
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
// now we check if it's one of the "special" cases:
|
||||
// -LYRICS: depending on the number of values, use USLT or TXXX (with description=LYRICS)
|
||||
if(key == "LYRICS" && values.size() == 1){
|
||||
UnsynchronizedLyricsFrame *frame = UnsynchronizedLyricsFrame();
|
||||
frame->setText(values.front());
|
||||
return frame;
|
||||
}
|
||||
// -URL: depending on the number of values, use WXXX or TXXX (with description=URL)
|
||||
if((key == "URL" || key.startsWith(urlPrefix)) && values.size() == 1){
|
||||
UserUrlLinkFrame *frame = UserUrlLinkFrame(String::UTF8);
|
||||
frame->setDescription(key == "URL" ? key : key.substr(urlPrefix.size()));
|
||||
frame->setUrl(values.front());
|
||||
return frame;
|
||||
}
|
||||
// -COMMENT: depending on the number of values, use COMM or TXXX (with description=COMMENT)
|
||||
if((key == "COMMENT" || key.startsWith(commentPrefix)) && values.size() == 1){
|
||||
CommentsFrame *frame = CommentsFrame(String::UTF8);
|
||||
frame->setDescription(key == "COMMENT" ? key : key.substr(commentPrefix.size()));
|
||||
frame->setText(values.front());
|
||||
return frame;
|
||||
}
|
||||
// if non of the above cases apply, we use a TXXX frame with the key as description
|
||||
return UserTextIdentificationFrame(key, values, String::UTF8);
|
||||
}
|
||||
|
||||
Frame::~Frame()
|
||||
{
|
||||
delete d;
|
||||
@@ -263,7 +307,7 @@ String::Type Frame::checkTextEncoding(const StringList &fields, String::Type enc
|
||||
return checkEncoding(fields, encoding, header()->version());
|
||||
}
|
||||
|
||||
static const uint frameTranslationSize = 50;
|
||||
static const uint frameTranslationSize = 51;
|
||||
static const char *frameTranslation[][2] = {
|
||||
// Text information frames
|
||||
{ "TALB", "ALBUM"},
|
||||
@@ -325,7 +369,7 @@ static const char *frameTranslation[][2] = {
|
||||
{ "WPUB", "PUBLISHERWEBPAGE" },
|
||||
//{ "WXXX", "URL"}, handled specially
|
||||
// Other frames
|
||||
//{ "COMM", "COMMENT" }, handled specially
|
||||
{ "COMM", "COMMENT" },
|
||||
//{ "USLT", "LYRICS" }, handled specially
|
||||
};
|
||||
|
||||
@@ -399,6 +443,24 @@ PropertyMap Frame::asProperties() const
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
||||
void Frame::splitProperties(const PropertyMap &original, PropertyMap &singleFrameProperties,
|
||||
PropertyMap &tiplProperties, PropertyMap &tmclProperties)
|
||||
{
|
||||
|
||||
singleFrameProperties.clear();
|
||||
tiplProperties.clear();
|
||||
tmclProperties.clear();
|
||||
for(PropertyMap::ConstIterator it = original.begin(); it != original.end(); ++it) {
|
||||
if(TextIdentificationFrame::involvedPeopleMap().contains(it->first))
|
||||
tiplProperties.insert(it->first, it->second);
|
||||
else if(it->first.startsWith(TextIdentificationFrame::instrumentPrefix))
|
||||
tmclProperties.insert(it->first, it->second);
|
||||
else
|
||||
singleFrameProperties.insert(it->first, it->second);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Frame::Header class
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -57,6 +57,14 @@ namespace TagLib {
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
|
||||
/*!
|
||||
* Creates a textual frame which corresponds to a single key in the PropertyMap
|
||||
* interface. These are all (User)TextIdentificationFrames except TIPL and TMCL,
|
||||
* all (User)URLLinkFrames, CommentsFrames, and UnsynchronizedLyricsFrame.
|
||||
*/
|
||||
static Frame *createTextualFrame(const String &key, const StringList &values);
|
||||
|
||||
/*!
|
||||
* Destroys this Frame instance.
|
||||
*/
|
||||
@@ -127,6 +135,23 @@ namespace TagLib {
|
||||
*/
|
||||
static ByteVector textDelimiter(String::Type t);
|
||||
|
||||
/*!
|
||||
* The string with which an instrument name is prefixed to build a key in a PropertyMap;
|
||||
* used to translate PropertyMaps to TMCL frames. In the current implementation, this
|
||||
* is "PERFORMER:".
|
||||
*/
|
||||
static const String instrumentPrefix;
|
||||
/*!
|
||||
* The PropertyMap key prefix which triggers the use of a COMM frame instead of a TXXX
|
||||
* frame for a non-standard key. In the current implementation, this is "COMMENT:".
|
||||
*/
|
||||
static const String commentPrefix;
|
||||
/*!
|
||||
* The PropertyMap key prefix which triggers the use of a WXXX frame instead of a TXX
|
||||
* frame for a non-standard key. In the current implementation, this is "URL:".
|
||||
*/
|
||||
static const String urlPrefix;
|
||||
|
||||
protected:
|
||||
class Header;
|
||||
|
||||
@@ -244,6 +269,23 @@ namespace TagLib {
|
||||
*/
|
||||
static String frameIDToKey(const ByteVector &);
|
||||
|
||||
|
||||
/*!
|
||||
* This helper function splits the PropertyMap \a original into three ProperytMaps
|
||||
* \a singleFrameProperties, \a tiplProperties, and \a tmclProperties, such that:
|
||||
* - \a singleFrameProperties contains only of keys which can be represented with
|
||||
* exactly one ID3 frame per key. In the current implementation
|
||||
* this is everything except for the fixed "involved people" keys and keys of the
|
||||
* form "TextIdentificationFrame::instrumentPrefix" + "instrument", which are
|
||||
* mapped to a TMCL frame.
|
||||
* - \a tiplProperties will consist of those keys that are present in
|
||||
* TextIdentificationFrame::involvedPeopleMap()
|
||||
* - \a tmclProperties contains the "musician credits" keys which should be mapped
|
||||
* to a TMCL frame
|
||||
*/
|
||||
static void splitProperties(const PropertyMap &original, PropertyMap &singleFrameProperties,
|
||||
PropertyMap &tiplProperties, PropertyMap &tmclProperties);
|
||||
|
||||
private:
|
||||
Frame(const Frame &);
|
||||
Frame &operator=(const Frame &);
|
||||
|
||||
@@ -344,160 +344,46 @@ PropertyMap ID3v2::Tag::properties() const
|
||||
|
||||
PropertyMap ID3v2::Tag::setProperties(const PropertyMap &origProps)
|
||||
{
|
||||
FrameList toRemove;
|
||||
PropertyMap properties = origProps;
|
||||
// first find out what frames to remove; we do not remove in-place
|
||||
// because that would invalidate FrameListMap iterators.
|
||||
// At the moment, we remove _all_ frames that don't contain unsupported data,
|
||||
// and create new ones in the next step; this is to avoid clumsy technicalities
|
||||
// arising when trying to do this more efficient. For example, if the current tag
|
||||
// contains one URL attribute stored in an WXXX frame, but the given \a properties
|
||||
// contain two URL values, we would need to remove the WXXX frame (which supports
|
||||
// only one value), and create a TXXX frame with description=URL.
|
||||
// The same may happen with COMM and USLT. Additionally, handling of TIPL and TMCL is
|
||||
// complicated.
|
||||
// In the future, someone might come up with a more clever sync algorithm. :-)
|
||||
for(FrameListMap::ConstIterator it = frameListMap().begin(); it != frameListMap().end(); ++it) {
|
||||
String key = Frame::frameIDToKey(it->first);
|
||||
// for unsupported (binary) frame types, as well as frames that need special treatment
|
||||
// (TXXX, WXXX, COMM, TMCL, TIPL, USLT), key will be String::null
|
||||
if(key.isNull())
|
||||
continue;
|
||||
// else: non-user text or url frame -> there should be only one frame of this type,
|
||||
// and it's asProperties() method should return a PropertyMap with exactly one key
|
||||
// and empty unsupportedData().
|
||||
if(it->second.size() != 1)
|
||||
debug("invalid ID3 tag: found more than one " + it->first + " frame");
|
||||
PropertyMap frameMap = it->second[0]->asProperties();
|
||||
if(properties.contains(key) && frameMap[key] == properties[key])
|
||||
properties.erase(key);
|
||||
else
|
||||
toRemove.append(it->second[0]);
|
||||
}
|
||||
|
||||
// now handle the special cases
|
||||
// first: TXXX frames
|
||||
FrameList &userTextFrames = frameList("TXXX");
|
||||
for(FrameList::ConstIterator it = userTextFrames.begin(); it != userTextFrames.end(); ++it) {
|
||||
PropertyMap frameMap = (*it)->asProperties();
|
||||
if(!frameMap.unsupportedData().isEmpty())
|
||||
// don't touch unsupported frames
|
||||
continue;
|
||||
// TXXX frames yield only one key, so it must be begin()->first
|
||||
String &key = frameMap.begin()->first;
|
||||
if(!Frame::keyToFrameID(key).isNull())
|
||||
// TXXX frame which a description (=key) for which there is a dedicated frame.
|
||||
// We don't want this, so remove the frame, the appropriate T*** or W*** frame
|
||||
// will be created later on.
|
||||
toRemove.append(*it);
|
||||
if(key.find(":") > 0)
|
||||
// colon-separated key: this should be inside a TMCL frame.
|
||||
toRemove.append(*it);
|
||||
// More (ugly) exceptions: If the user provides more than one COMMENT, LYRICS, or URL
|
||||
// tag, we store all of these in a TXXX, because COMM, USLT and WXXX. Otherwise there
|
||||
// should not be such a TXXX frame.
|
||||
if(key == "COMMENT") {
|
||||
if(properties.contains("COMMENT")
|
||||
&& properties["COMMENT"].size() >= 2
|
||||
&& properties["COMMENT"] == frameMap.begin()->second)
|
||||
properties.erase("COMMENT");
|
||||
FrameList framesToDelete;
|
||||
// we split up the PropertyMap into the "normal" keys and the "complicated" ones,
|
||||
// which are those according to TIPL or TMCL frames.
|
||||
PropertyMap properties;
|
||||
PropertyMap tiplProperties;
|
||||
PropertyMap tmclProperties;
|
||||
Frame::splitProperties(origProps, properties, tiplProperties, tmclProperties);
|
||||
for(FrameListMap::ConstIterator it = frameListMap().begin(); it != frameListMap().end(); ++it){
|
||||
for(FrameList::ConstIterator lit = it->second.begin(); lit != it->second.end(); ++lit){
|
||||
PropertyMap frameProperties = (*lit)->asProperties();
|
||||
if(it->first == "TIPL")
|
||||
if (tiplProperties != frameProperties)
|
||||
framesToDelete.append(*lit);
|
||||
else
|
||||
tiplProperties.erase(frameProperties);
|
||||
else if(it->first == "TMCL")
|
||||
if (tmclProperties != frameProperties)
|
||||
framesToDelete.append(*lit);
|
||||
else
|
||||
tmclProperties.erase(frameProperties);
|
||||
else if(!properties.contains(frameProperties))
|
||||
framesToDelete.append(*lit);
|
||||
else
|
||||
toRemove.append(*it);
|
||||
}else if(key == "LYRICS") {
|
||||
if(properties.contains("LYRICS")
|
||||
&& properties["LYRICS"].size() >= 2
|
||||
&& properties["LYRICS"] == frameMap.begin()->second)
|
||||
properties.erase("LYRICS");
|
||||
else
|
||||
toRemove.append(*it);
|
||||
}else if(key == "URL") {
|
||||
if(properties.contains("URL")
|
||||
&& properties["URL"].size() >= 2
|
||||
&& properties["URL"] == frameMap.begin()->second)
|
||||
properties.erase("URL");
|
||||
else
|
||||
toRemove.append(*it);
|
||||
properties.erase(frameProperties);
|
||||
}
|
||||
}
|
||||
|
||||
// next: WXXX frames
|
||||
FrameList &userUrlFrames = frameList("WXXX");
|
||||
for(FrameList::ConstIterator it = userUrlFrames.begin(); it != userUrlFrames.end(); ++it) {
|
||||
PropertyMap frameMap = (*it)->asProperties();
|
||||
if(!frameMap.unsupportedData().isEmpty())
|
||||
// don't touch unsupported frames
|
||||
continue;
|
||||
// WXXX frames yield only one key, so it must be begin()->first
|
||||
String &key = frameMap.begin()->first;
|
||||
if(!Frame::keyToFrameID(key).isNull())
|
||||
// WXXX frame which a description (=key) for which there is a dedicated frame.
|
||||
// We don't want this, so remove the frame, the appropriate T*** or W*** frame
|
||||
// will be created later on.
|
||||
toRemove.append(*it);
|
||||
else if(key.find(":") > 0)
|
||||
// colon-separated key: this should be inside a TMCL frame.
|
||||
toRemove.append(*it);
|
||||
// More exceptions: we don't allow COMMENT and LYRICS in WXXX; they should be in COMM and USLT
|
||||
// (or TXXX, see above).
|
||||
else if(key == "COMMENT" || key == "LYRICS")
|
||||
toRemove.append(*it);
|
||||
// now, the key is either URL or some other string that neither has a dedicated text frame, nor
|
||||
// a colon. We accept the frame if it's contents match the values in properties. However, if
|
||||
// key != URL and the values are changed, they will be stored inside a TXXX frame instead, since
|
||||
// we can't distinguish free-form text from free-form URL keys (possible fix: use URL:REASON like
|
||||
// in TMCL / TIPL?).
|
||||
else if(properties.contains(key) && properties[key] == frameMap.begin()->second)
|
||||
properties.erase(key);
|
||||
else
|
||||
toRemove.append(*it);
|
||||
}
|
||||
for(FrameList::ConstIterator it = toRemove.begin(); it != toRemove.end(); ++it)
|
||||
for(FrameList::ConstIterator it = framesToDelete.begin(); it != framesToDelete.end(); ++it)
|
||||
removeFrame(*it);
|
||||
|
||||
// next: TIPL
|
||||
PropertyMap existingTipl;
|
||||
if(!frameList("TIPL").isEmpty())
|
||||
existingTipl = frameList("TIPL").front()->asProperties();
|
||||
PropertyMap requestedTipl;
|
||||
KeyConversionMap::ConstIterator it = TextIdentificationFrame::involvedPeopleMap().begin();
|
||||
bool rebuildTipl = false;
|
||||
for(; it != TextIdentificationFrame::involvedPeopleMap().end(); ++it) {
|
||||
if(properties.contains(it->first)){
|
||||
requestedTipl.insert(it->first, properties[it->first]);
|
||||
properties.erase(it->first); // it's ensured now that this key gets handled correctly
|
||||
if(!existingTipl.contains(it->first) || existingTipl[it->first] != requestedTipl[it->first])
|
||||
rebuildTipl = true;
|
||||
} else if(existingTipl.contains(it->first))
|
||||
rebuildTipl = true;
|
||||
}
|
||||
if(rebuildTipl){
|
||||
removeFrames("TIPL");
|
||||
addFrame(TextIdentificationFrame::createTIPLFrame(requestedTipl));
|
||||
}
|
||||
|
||||
// next: create frames for everything still in properties except for TMCL ("PERFORMER:<instrument>")
|
||||
// keys, which are collected in a dedicated map
|
||||
PropertyMap requestedTmcl;
|
||||
for(PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it){
|
||||
if(it->first.find(":") != -1)
|
||||
requestedTmcl.insert(it->first, it->second);
|
||||
else{
|
||||
// phew. Now we are in the simple case that our key=<value list> pair can be represented by a
|
||||
// single frame, either a T*** (not TIPL, TMCL) or W*** frame.
|
||||
ByteVector id = Frame::keyToFrameID(it->first);
|
||||
}
|
||||
}
|
||||
|
||||
// next: TMCL
|
||||
PropertyMap existingTmcl;
|
||||
if(!frameList("TMCL").isEmpty())
|
||||
existingTmcl = frameList("TMCL").front()->asProperties();
|
||||
bool rebuildTmcl = false;
|
||||
// search for TMCL keys ("PERFORMER:<instrument>") in properties
|
||||
for(PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it){
|
||||
if(it->first.find(":") != -1)
|
||||
requestedTmcl.insert(it->first, it->second);
|
||||
}
|
||||
// now create remaining frames:
|
||||
// start with the involved people list (TIPL)
|
||||
if(!tiplProperties.isEmpty())
|
||||
addFrame(TextIdentificationFrame::createTIPLFrame(tiplProperties));
|
||||
// proceed with the musician credit list (TMCL)
|
||||
if(!tmclProperties.isEmpty())
|
||||
addFrame(TextIdentificationFrame::createTMCLFrame(tmclProperties));
|
||||
// now create the "one key per frame" frames
|
||||
for(PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it)
|
||||
addFrame(Frame::createTextualFrame(it->first, it->second));
|
||||
return PropertyMap; // ID3 implements the complete PropertyMap interface, so an empty map is returned
|
||||
}
|
||||
|
||||
ByteVector ID3v2::Tag::render() const
|
||||
|
||||
@@ -92,16 +92,6 @@ Ogg::XiphComment *Ogg::FLAC::File::tag() const
|
||||
return d->comment;
|
||||
}
|
||||
|
||||
TagLib::TagDict Ogg::FLAC::File::toDict(void) const
|
||||
{
|
||||
return d->comment->toDict();
|
||||
}
|
||||
|
||||
void Ogg::FLAC::File::fromDict(const TagDict &dict)
|
||||
{
|
||||
d->comment->fromDict(dict);
|
||||
}
|
||||
|
||||
Properties *Ogg::FLAC::File::audioProperties() const
|
||||
{
|
||||
return d->properties;
|
||||
|
||||
@@ -89,18 +89,6 @@ namespace TagLib {
|
||||
*/
|
||||
virtual XiphComment *tag() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified tag dictionary interface -- export function.
|
||||
* Returns the contents of the Ogg::XiphComment as TagDict.
|
||||
*/
|
||||
TagDict toDict() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified tag dictionary interface -- import function.
|
||||
* Matches the TagDict's contents to the XiphComment of the file.
|
||||
*/
|
||||
void fromDict(const TagDict &);
|
||||
|
||||
/*!
|
||||
* Returns the FLAC::Properties for this file. If no audio properties
|
||||
* were read then this will return a null pointer.
|
||||
|
||||
@@ -82,16 +82,6 @@ Ogg::XiphComment *Speex::File::tag() const
|
||||
return d->comment;
|
||||
}
|
||||
|
||||
TagLib::TagDict Ogg::Speex::File::toDict(void) const
|
||||
{
|
||||
return d->comment->toDict();
|
||||
}
|
||||
|
||||
void Ogg::Speex::File::fromDict(const TagDict &dict)
|
||||
{
|
||||
d->comment->fromDict(dict);
|
||||
}
|
||||
|
||||
Speex::Properties *Speex::File::audioProperties() const
|
||||
{
|
||||
return d->properties;
|
||||
|
||||
@@ -82,17 +82,6 @@ namespace TagLib {
|
||||
* TagLib::File::tag().
|
||||
*/
|
||||
virtual Ogg::XiphComment *tag() const;
|
||||
/*!
|
||||
* Implements the unified tag dictionary interface -- export function.
|
||||
* Returns the contents of the Ogg::XiphComment as TagDict.
|
||||
*/
|
||||
TagDict toDict() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified tag dictionary interface -- import function.
|
||||
* Matches the TagDict's contents to the XiphComment of the file.
|
||||
*/
|
||||
void fromDict(const TagDict &);
|
||||
|
||||
/*!
|
||||
* Returns the Speex::Properties for this file. If no audio properties
|
||||
|
||||
@@ -85,14 +85,14 @@ Ogg::XiphComment *Vorbis::File::tag() const
|
||||
return d->comment;
|
||||
}
|
||||
|
||||
TagLib::TagDict Ogg::Vorbis::File::toDict(void) const
|
||||
PropertyMap Vorbis::File::properties() const
|
||||
{
|
||||
return d->comment->toDict();
|
||||
return d->comment->properties();
|
||||
}
|
||||
|
||||
void Ogg::Vorbis::File::fromDict(const TagDict &dict)
|
||||
PropertyMap Vorbis::File::setProperties(const PropertyMap &properties)
|
||||
{
|
||||
d->comment->fromDict(dict);
|
||||
return d->comment->setProperties(properties);
|
||||
}
|
||||
|
||||
Vorbis::Properties *Vorbis::File::audioProperties() const
|
||||
|
||||
@@ -90,17 +90,19 @@ namespace TagLib {
|
||||
*/
|
||||
virtual Ogg::XiphComment *tag() const;
|
||||
|
||||
|
||||
/*!
|
||||
* Implements the unified tag dictionary interface -- export function.
|
||||
* Returns the contents of the Ogg::XiphComment as TagDict.
|
||||
* Implements the unified property interface -- export function.
|
||||
* This forwards directly to XiphComment::properties().
|
||||
*/
|
||||
TagDict toDict() const;
|
||||
PropertyMap properties() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified tag dictionary interface -- import function.
|
||||
* Matches the TagDict's contents to the XiphComment of the file.
|
||||
* Like properties(), this is a forwarder to the file's XiphComment.
|
||||
*/
|
||||
void fromDict(const TagDict &);
|
||||
PropertyMap setProperties(const PropertyMap &);
|
||||
|
||||
/*!
|
||||
* Returns the Vorbis::Properties for this file. If no audio properties
|
||||
* were read then this will return a null pointer.
|
||||
|
||||
@@ -84,15 +84,14 @@ ID3v2::Tag *RIFF::AIFF::File::tag() const
|
||||
return d->tag;
|
||||
}
|
||||
|
||||
TagLib::TagDict RIFF::AIFF::File::toDict(void) const
|
||||
PropertyMap RIFF::AIFF::File::properties() const
|
||||
{
|
||||
return d->tag->toDict();
|
||||
|
||||
return d->tag->properties();
|
||||
}
|
||||
|
||||
void RIFF::AIFF::File::fromDict(const TagDict &dict)
|
||||
PropertyMap RIFF::AIFF::File::setProperties(const PropertyMap &properties)
|
||||
{
|
||||
d->tag->fromDict(dict);
|
||||
return d->tag->setProperties(properties);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -84,16 +84,16 @@ namespace TagLib {
|
||||
virtual ID3v2::Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified tag dictionary interface -- export function.
|
||||
* This method forwards to ID3v2::Tag::toDict.
|
||||
* Implements the unified property interface -- export function.
|
||||
* This method forwards to ID3v2::Tag::properties().
|
||||
*/
|
||||
TagDict toDict() const;
|
||||
PropertyMap properties() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified tag dictionary interface -- import function.
|
||||
* This method forwards to ID3v2::Tag::fromDict.
|
||||
* Implements the unified property interface -- import function.
|
||||
* This method forwards to ID3v2::Tag::setProperties().
|
||||
*/
|
||||
void fromDict(const TagDict &);
|
||||
PropertyMap setProperties(const PropertyMap &);
|
||||
|
||||
/*!
|
||||
* Returns the AIFF::Properties for this file. If no audio properties
|
||||
|
||||
@@ -84,14 +84,14 @@ ID3v2::Tag *RIFF::WAV::File::tag() const
|
||||
return d->tag;
|
||||
}
|
||||
|
||||
TagLib::TagDict RIFF::WAV::File::toDict(void) const
|
||||
PropertyMap RIFF::WAV::File::properties() const
|
||||
{
|
||||
return d->tag->toDict();
|
||||
return d->tag->properties();
|
||||
}
|
||||
|
||||
void RIFF::WAV::File::fromDict(const TagDict &dict)
|
||||
PropertyMap RIFF::WAV::File::setProperties(const PropertyMap &properties)
|
||||
{
|
||||
d->tag->fromDict(dict);
|
||||
return d->tag->setProperties(properties);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -84,16 +84,16 @@ namespace TagLib {
|
||||
virtual ID3v2::Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified tag dictionary interface -- export function.
|
||||
* This method forwards to ID3v2::Tag::toDict.
|
||||
* Implements the unified property interface -- export function.
|
||||
* This method forwards to ID3v2::Tag::properties().
|
||||
*/
|
||||
TagDict toDict() const;
|
||||
PropertyMap properties() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified tag dictionary interface -- import function.
|
||||
* This method forwards to ID3v2::Tag::fromDict.
|
||||
* Implements the unified property interface -- import function.
|
||||
* This method forwards to ID3v2::Tag::setProperties().
|
||||
*/
|
||||
void fromDict(const TagDict &);
|
||||
PropertyMap setProperties(const PropertyMap &);
|
||||
|
||||
/*!
|
||||
* Returns the WAV::Properties for this file. If no audio properties
|
||||
|
||||
@@ -91,11 +91,22 @@ namespace TagLib {
|
||||
*/
|
||||
bool contains(const String &key) const;
|
||||
|
||||
/*!
|
||||
* Returns true if this map contains all keys of \a other
|
||||
* and the values coincide for that keys.
|
||||
*/
|
||||
bool contains(const PropertyMap &other) const;
|
||||
|
||||
/*!
|
||||
* Erase the \a key and its values from the map.
|
||||
*/
|
||||
PropertyMap &erase(const String &key);
|
||||
|
||||
/*!
|
||||
* Erases from this map all keys that appear in \a other.
|
||||
*/
|
||||
PropertyMap &erase(const PropertyMap &other);
|
||||
|
||||
/*!
|
||||
* Merge the contents of \a other into this PropertyMap.
|
||||
* If a key is contained in both maps, the values of the second
|
||||
|
||||
Reference in New Issue
Block a user