mirror of
https://github.com/taglib/taglib.git
synced 2025-06-04 01:28:21 -04:00
Some preliminary work for unified dictionary tag interface support.
- toDict() and fromDict() for XiphComments - toDict() for ID3v2 Tags
This commit is contained in:
parent
bec3875b94
commit
b262180857
@ -54,6 +54,7 @@ set(tag_HDRS
|
||||
mpeg/xingheader.h
|
||||
mpeg/id3v1/id3v1tag.h
|
||||
mpeg/id3v1/id3v1genres.h
|
||||
mpeg/id3v2/id3v2dicttools.h
|
||||
mpeg/id3v2/id3v2extendedheader.h
|
||||
mpeg/id3v2/id3v2frame.h
|
||||
mpeg/id3v2/id3v2header.h
|
||||
@ -137,6 +138,7 @@ set(id3v1_SRCS
|
||||
)
|
||||
|
||||
set(id3v2_SRCS
|
||||
mpeg/id3v2/id3v2dicttools.cpp
|
||||
mpeg/id3v2/id3v2framefactory.cpp
|
||||
mpeg/id3v2/id3v2synchdata.cpp
|
||||
mpeg/id3v2/id3v2tag.cpp
|
||||
|
156
taglib/mpeg/id3v2/id3v2dicttools.cpp
Normal file
156
taglib/mpeg/id3v2/id3v2dicttools.cpp
Normal file
@ -0,0 +1,156 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2011 by Michael Helmling
|
||||
email : supermihi@web.de
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
#include "tdebug.h"
|
||||
#include "id3v2dicttools.h"
|
||||
#include "tmap.h"
|
||||
namespace TagLib {
|
||||
namespace ID3v2 {
|
||||
|
||||
/*!
|
||||
* A map of translations frameID <-> tag used by the unified dictionary interface.
|
||||
*/
|
||||
static const uint numid3frames = 55;
|
||||
static const char *id3frames[][2] = {
|
||||
// Text information frames
|
||||
{ "TALB", "ALBUM"},
|
||||
{ "TBPM", "BPM" },
|
||||
{ "TCOM", "COMPOSER" },
|
||||
{ "TCON", "GENRE" },
|
||||
{ "TCOP", "COPYRIGHT" },
|
||||
{ "TDEN", "ENCODINGTIME" },
|
||||
{ "TDLY", "PLAYLISTDELAY" },
|
||||
{ "TDOR", "ORIGINALRELEASETIME" },
|
||||
{ "TDRC", "DATE" },
|
||||
// { "TRDA", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4
|
||||
// { "TDAT", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4
|
||||
// { "TYER", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4
|
||||
// { "TIME", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4
|
||||
{ "TDRL", "RELEASETIME" },
|
||||
{ "TDTG", "TAGGINGTIME" },
|
||||
{ "TENC", "ENCODEDBY" },
|
||||
{ "TEXT", "LYRICIST" },
|
||||
{ "TFLT", "FILETYPE" },
|
||||
{ "TIPL", "INVOLVEDPEOPLE" },
|
||||
{ "TIT1", "CONTENTGROUP" },
|
||||
{ "TIT2", "TITLE"},
|
||||
{ "TIT3", "SUBTITLE" },
|
||||
{ "TKEY", "INITIALKEY" },
|
||||
{ "TLAN", "LANGUAGE" },
|
||||
{ "TLEN", "LENGTH" },
|
||||
{ "TMCL", "MUSICIANCREDITS" },
|
||||
{ "TMED", "MEDIATYPE" },
|
||||
{ "TMOO", "MOOD" },
|
||||
{ "TOAL", "ORIGINALALBUM" },
|
||||
{ "TOFN", "ORIGINALFILENAME" },
|
||||
{ "TOLY", "ORIGINALLYRICIST" },
|
||||
{ "TOPE", "ORIGINALARTIST" },
|
||||
{ "TOWN", "OWNER" },
|
||||
{ "TPE1", "ARTIST"},
|
||||
{ "TPE2", "PERFORMER" },
|
||||
{ "TPE3", "CONDUCTOR" },
|
||||
{ "TPE4", "ARRANGER" },
|
||||
{ "TPOS", "DISCNUMBER" },
|
||||
{ "TPRO", "PRODUCEDNOTICE" },
|
||||
{ "TPUB", "PUBLISHER" },
|
||||
{ "TRCK", "TRACKNUMBER" },
|
||||
{ "TRSN", "RADIOSTATION" },
|
||||
{ "TRSO", "RADIOSTATIONOWNER" },
|
||||
{ "TSOA", "ALBUMSORT" },
|
||||
{ "TSOP", "ARTISTSORT" },
|
||||
{ "TSOT", "TITLESORT" },
|
||||
{ "TSRC", "ISRC" },
|
||||
{ "TSSE", "ENCODING" },
|
||||
|
||||
// URL frames
|
||||
{ "WCOP", "COPYRIGHTURL" },
|
||||
{ "WOAF", "FILEWEBPAGE" },
|
||||
{ "WOAR", "ARTISTWEBPAGE" },
|
||||
{ "WOAS", "AUDIOSOURCEWEBPAGE" },
|
||||
{ "WORS", "RADIOSTATIONWEBPAGE" },
|
||||
{ "WPAY", "PAYMENTWEBPAGE" },
|
||||
{ "WPUB", "PUBLISHERWEBPAGE" },
|
||||
{ "WXXX", "URL"},
|
||||
|
||||
// Other frames
|
||||
{ "COMM", "COMMENT" },
|
||||
{ "USLT", "LYRICS" },
|
||||
{ "UFID", "UNIQUEIDENTIFIER" },
|
||||
};
|
||||
|
||||
// list of frameIDs that are ignored by the unified dictionary interface
|
||||
static const uint ignoredFramesSize = 6;
|
||||
static const char *ignoredFrames[] = {
|
||||
"TCMP", // illegal 'Part of Compilation' frame set by iTunes (see http://www.id3.org/Compliance_Issues)
|
||||
"GEOB", // no way to handle a general encapsulated object by the dict interface
|
||||
"PRIV", // private frames
|
||||
"APIC", // attached picture -- TODO how could we do this?
|
||||
"POPM", // popularimeter
|
||||
"RVA2", // relative volume
|
||||
};
|
||||
|
||||
// list of deprecated frames and their successors
|
||||
static const uint deprecatedFramesSize = 4;
|
||||
static const char *deprecatedFrames[][2] = {
|
||||
{"TRDA", "TDRC"}, // 2.3 -> 2.4 (http://en.wikipedia.org/wiki/ID3)
|
||||
{"TDAT", "TDRC"}, // 2.3 -> 2.4
|
||||
{"TYER", "TDRC"}, // 2.3 -> 2.4
|
||||
{"TIME", "TDRC"}, // 2.3 -> 2.4
|
||||
};
|
||||
|
||||
String frameIDToTagName(const ByteVector &id) {
|
||||
static Map<ByteVector, String> m;
|
||||
if (m.isEmpty())
|
||||
for (size_t i = 0; i < numid3frames; ++i)
|
||||
m[id3frames[i][0]] = id3frames[i][1];
|
||||
|
||||
if (m.contains(id))
|
||||
return m[id];
|
||||
if (deprecationMap().contains(id))
|
||||
return m[deprecationMap()[id]];
|
||||
debug("unknown frame ID: " + id);
|
||||
return "UNKNOWNID3TAG"; //TODO: implement this nicer
|
||||
}
|
||||
|
||||
bool isIgnored(const ByteVector& id) {
|
||||
List<ByteVector> ignoredList;
|
||||
if (ignoredList.isEmpty())
|
||||
for (uint i = 0; i < ignoredFramesSize; ++i)
|
||||
ignoredList.append(ignoredFrames[i]);
|
||||
return ignoredList.contains(id);
|
||||
}
|
||||
|
||||
FrameIDMap deprecationMap() {
|
||||
static FrameIDMap depMap;
|
||||
if (depMap.isEmpty())
|
||||
for(uint i = 0; i < deprecatedFramesSize; ++i)
|
||||
depMap[deprecatedFrames[i][0]] = deprecatedFrames[i][1];
|
||||
return depMap;
|
||||
}
|
||||
|
||||
bool isDeprecated(const ByteVector& id) {
|
||||
return deprecationMap().contains(id);
|
||||
}
|
||||
}
|
||||
}
|
54
taglib/mpeg/id3v2/id3v2dicttools.h
Normal file
54
taglib/mpeg/id3v2/id3v2dicttools.h
Normal file
@ -0,0 +1,54 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2011 by Michael Helmling
|
||||
email : supermihi@web.de
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef ID3V2DICTTOOLS_H_
|
||||
#define ID3V2DICTTOOLS_H_
|
||||
|
||||
#include "tstringlist.h"
|
||||
#include "taglib_export.h"
|
||||
#include "tmap.h"
|
||||
|
||||
namespace TagLib {
|
||||
namespace ID3v2 {
|
||||
/*!
|
||||
* This file contains methods used by the unified dictionary interface for ID3v2 tags
|
||||
* (tag name conversion, handling of un-translatable frameIDs, ...).
|
||||
*/
|
||||
typedef Map<ByteVector, ByteVector> FrameIDMap;
|
||||
|
||||
String TAGLIB_EXPORT frameIDToTagName(const ByteVector &id);
|
||||
|
||||
bool TAGLIB_EXPORT isIgnored(const ByteVector &);
|
||||
|
||||
FrameIDMap TAGLIB_EXPORT deprecationMap();
|
||||
|
||||
bool TAGLIB_EXPORT isDeprecated(const ByteVector&);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif /* ID3V2DICTTOOLS_H_ */
|
@ -31,11 +31,15 @@
|
||||
#include "id3v2extendedheader.h"
|
||||
#include "id3v2footer.h"
|
||||
#include "id3v2synchdata.h"
|
||||
|
||||
#include "id3v2dicttools.h"
|
||||
#include "tbytevector.h"
|
||||
#include "id3v1genres.h"
|
||||
|
||||
#include "frames/textidentificationframe.h"
|
||||
#include "frames/commentsframe.h"
|
||||
#include "frames/urllinkframe.h"
|
||||
#include "frames/uniquefileidentifierframe.h"
|
||||
#include "frames/unsynchronizedlyricsframe.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
@ -324,9 +328,115 @@ void ID3v2::Tag::removeFrame(Frame *frame, bool del)
|
||||
|
||||
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);
|
||||
FrameList l = d->frameListMap[id];
|
||||
for(FrameList::Iterator it = l.begin(); it != l.end(); ++it)
|
||||
removeFrame(*it, true);
|
||||
}
|
||||
|
||||
TagDict ID3v2::Tag::toDict() const
|
||||
{
|
||||
TagDict dict;
|
||||
FrameList::ConstIterator frameIt = frameList().begin();
|
||||
for (; frameIt != frameList().end(); ++frameIt) {
|
||||
ByteVector id = (*frameIt)->frameID();
|
||||
|
||||
if (isIgnored(id)) {
|
||||
debug("found ignored id3 frame " + id);
|
||||
continue;
|
||||
}
|
||||
if (isDeprecated(id)) {
|
||||
debug("found deprecated id3 frame " + id);
|
||||
continue;
|
||||
}
|
||||
if (id[0] == 'T') {
|
||||
if (id == "TXXX") {
|
||||
const UserTextIdentificationFrame *uframe
|
||||
= dynamic_cast< const UserTextIdentificationFrame* >(*frameIt);
|
||||
String tagName = uframe->description();
|
||||
StringList l(uframe->fieldList());
|
||||
// this is done because taglib stores the description also as first entry
|
||||
// in the field list. (why?)
|
||||
//
|
||||
if (l.contains(tagName))
|
||||
l.erase(l.find(tagName));
|
||||
// handle user text frames set by the QuodLibet / exFalso package,
|
||||
// which sets the description to QuodLibet::<tagName> instead of simply
|
||||
// <tagName>.
|
||||
int pos = tagName.find("::");
|
||||
tagName = (pos != -1) ? tagName.substr(pos+2) : tagName;
|
||||
dict[tagName.upper()].append(l);
|
||||
}
|
||||
else {
|
||||
const TextIdentificationFrame* tframe
|
||||
= dynamic_cast< const TextIdentificationFrame* >(*frameIt);
|
||||
String tagName = frameIDToTagName(id);
|
||||
StringList l = tframe->fieldList();
|
||||
if (tagName == "GENRE") {
|
||||
// Special case: Support ID3v1-style genre numbers. They are not officially supported in
|
||||
// ID3v2, however it seems that still a lot of programs use them.
|
||||
//
|
||||
for (StringList::Iterator lit = l.begin(); lit != l.end(); ++lit) {
|
||||
bool ok = false;
|
||||
int test = lit->toInt(&ok); // test if the genre value is an integer
|
||||
if (ok) {
|
||||
*lit = ID3v1::genre(test);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (tagName == "DATE") {
|
||||
for (StringList::Iterator lit = l.begin(); lit != l.end(); ++lit) {
|
||||
// ID3v2 specifies ISO8601 timestamps which contain a 'T' as separator between date and time.
|
||||
// Since this is unusual in other formats, the T is removed.
|
||||
//
|
||||
int tpos = lit->find("T");
|
||||
if (tpos != -1)
|
||||
(*lit)[tpos] = ' ';
|
||||
}
|
||||
}
|
||||
dict[tagName].append(l);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (id[0] == 'W') {
|
||||
if (id == "WXXX") {
|
||||
const UserUrlLinkFrame *uframe = dynamic_cast< const UserUrlLinkFrame* >(*frameIt);
|
||||
String tagname = uframe->description().upper();
|
||||
if (tagname == "")
|
||||
tagname = "URL";
|
||||
dict[tagname].append(uframe->url());
|
||||
}
|
||||
else {
|
||||
const UrlLinkFrame* uframe = dynamic_cast< const UrlLinkFrame* >(*frameIt);
|
||||
dict[frameIDToTagName(id)].append(uframe->url());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (id == "COMM") {
|
||||
const CommentsFrame *cframe = dynamic_cast< const CommentsFrame* >(*frameIt);
|
||||
String tagName = cframe->description().upper();
|
||||
if (tagName.isEmpty())
|
||||
tagName = "COMMENT";
|
||||
dict[tagName].append(cframe->text());
|
||||
continue;
|
||||
}
|
||||
if (id == "USLT") {
|
||||
const UnsynchronizedLyricsFrame *uframe
|
||||
= dynamic_cast< const UnsynchronizedLyricsFrame* >(*frameIt);
|
||||
dict["LYRICS"].append(uframe->text());
|
||||
continue;
|
||||
}
|
||||
if (id == "UFID") {
|
||||
const UniqueFileIdentifierFrame *uframe
|
||||
= dynamic_cast< const UniqueFileIdentifierFrame* >(*frameIt);
|
||||
String value = uframe->identifier();
|
||||
if (!uframe->owner().isEmpty())
|
||||
value.append(" [" + uframe->owner() + "]");
|
||||
dict["UNIQUEIDENTIFIER"].append(value);
|
||||
continue;
|
||||
}
|
||||
debug("unknown frame ID: " + id);
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
ByteVector ID3v2::Tag::render() const
|
||||
|
@ -260,6 +260,16 @@ namespace TagLib {
|
||||
*/
|
||||
void removeFrames(const ByteVector &id);
|
||||
|
||||
/*!
|
||||
* Implements the unified tag dictionary interface -- export function.
|
||||
*/
|
||||
TagDict toDict() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified tag dictionary interface -- import function.
|
||||
*/
|
||||
void fromDict(const TagDict &);
|
||||
|
||||
/*!
|
||||
* Render the tag back to binary data, suitable to be written to disk.
|
||||
*/
|
||||
|
@ -188,6 +188,47 @@ const Ogg::FieldListMap &Ogg::XiphComment::fieldListMap() const
|
||||
return d->fieldListMap;
|
||||
}
|
||||
|
||||
TagDict Ogg::XiphComment::toDict() const
|
||||
{
|
||||
return d->fieldListMap;
|
||||
}
|
||||
|
||||
void Ogg::XiphComment::fromDict(const TagDict &tagDict)
|
||||
{
|
||||
// check which keys are to be deleted
|
||||
StringList toRemove;
|
||||
FieldListMap::ConstIterator it = d->fieldListMap.begin();
|
||||
for(; it != d->fieldListMap.end(); ++it) {
|
||||
if (!tagDict.contains(it->first))
|
||||
toRemove.append(it->first);
|
||||
}
|
||||
|
||||
StringList::ConstIterator removeIt = toRemove.begin();
|
||||
for (; removeIt != toRemove.end(); ++removeIt)
|
||||
removeField(*removeIt);
|
||||
|
||||
/* now go through keys in tagDict and check that the values match those in the xiph comment */
|
||||
TagDict::ConstIterator tagIt = tagDict.begin();
|
||||
for (; tagIt != tagDict.end(); ++tagIt)
|
||||
{
|
||||
if (!d->fieldListMap.contains(tagIt->first) || !(tagIt->second == d->fieldListMap[tagIt->first])) {
|
||||
const StringList &sl = tagIt->second;
|
||||
if(sl.size() == 0) {
|
||||
// zero size string list -> remove the tag with all values
|
||||
removeField(tagIt->first);
|
||||
}
|
||||
else {
|
||||
// replace all strings in the list for the tag
|
||||
StringList::ConstIterator valueIterator = sl.begin();
|
||||
addField(tagIt->first, *valueIterator, true);
|
||||
++valueIterator;
|
||||
for(; valueIterator != sl.end(); ++valueIterator)
|
||||
addField(tagIt->first, *valueIterator, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String Ogg::XiphComment::vendorID() const
|
||||
{
|
||||
return d->vendorID;
|
||||
|
@ -140,6 +140,16 @@ namespace TagLib {
|
||||
*/
|
||||
const FieldListMap &fieldListMap() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified tag dictionary interface -- export function.
|
||||
*/
|
||||
TagDict toDict() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified tag dictionary interface -- import function.
|
||||
*/
|
||||
void fromDict(const TagDict &);
|
||||
|
||||
/*!
|
||||
* Returns the vendor ID of the Ogg Vorbis encoder. libvorbis 1.0 as the
|
||||
* most common case always returns "Xiph.Org libVorbis I 20020717".
|
||||
|
@ -28,9 +28,17 @@
|
||||
|
||||
#include "taglib_export.h"
|
||||
#include "tstring.h"
|
||||
#include "tmap.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
/*!
|
||||
* This is used for the unified dictionary interface: the tags of a file are
|
||||
* represented as a dictionary mapping a string (the tag name) to a list of
|
||||
* strings (the values).
|
||||
*/
|
||||
typedef Map<String, StringList> TagDict;
|
||||
|
||||
//! A simple, generic interface to common audio meta data fields
|
||||
|
||||
/*!
|
||||
|
BIN
tests/data/test.ogg
Normal file
BIN
tests/data/test.ogg
Normal file
Binary file not shown.
@ -67,6 +67,7 @@ class TestID3v2 : public CppUnit::TestFixture
|
||||
CPPUNIT_TEST(testDowngradeTo23);
|
||||
// CPPUNIT_TEST(testUpdateFullDate22); TODO TYE+TDA should be upgraded to TDRC together
|
||||
CPPUNIT_TEST(testCompressedFrameWithBrokenLength);
|
||||
CPPUNIT_TEST(testDictInterface);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
@ -547,6 +548,29 @@ public:
|
||||
CPPUNIT_ASSERT_EQUAL(TagLib::uint(86414), frame->picture().size());
|
||||
}
|
||||
|
||||
void testDictInterface()
|
||||
{
|
||||
ScopedFileCopy copy("rare_frames", ".mp3");
|
||||
string newname = copy.fileName();
|
||||
MPEG::File f(newname.c_str());
|
||||
TagDict dict = f.ID3v2Tag(false)->toDict();
|
||||
CPPUNIT_ASSERT_EQUAL(uint(7), dict.size());
|
||||
CPPUNIT_ASSERT_EQUAL(String("userTextData1"), dict["USERTEXTDESCRIPTION1"][0]);
|
||||
CPPUNIT_ASSERT_EQUAL(String("userTextData2"), dict["USERTEXTDESCRIPTION1"][1]);
|
||||
CPPUNIT_ASSERT_EQUAL(String("userTextData1"), dict["USERTEXTDESCRIPTION2"][0]);
|
||||
CPPUNIT_ASSERT_EQUAL(String("userTextData2"), dict["USERTEXTDESCRIPTION2"][1]);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(String("Pop"), dict["GENRE"][0]);
|
||||
CPPUNIT_ASSERT_EQUAL(String("Pop"), dict["GENRE"][0]);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(String("http://a.user.url"), dict["USERURL"][0]);
|
||||
CPPUNIT_ASSERT_EQUAL(String("http://a.user.url/with/empty/description"), dict["URL"][0]);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(String("12345678 [supermihi@web.de]"), dict["UNIQUEIDENTIFIER"][0]);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(String("A COMMENT"), dict["COMMENT"][0]);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(TestID3v2);
|
||||
|
@ -17,6 +17,8 @@ class TestOGG : public CppUnit::TestFixture
|
||||
CPPUNIT_TEST_SUITE(TestOGG);
|
||||
CPPUNIT_TEST(testSimple);
|
||||
CPPUNIT_TEST(testSplitPackets);
|
||||
CPPUNIT_TEST(testDictInterface1);
|
||||
CPPUNIT_TEST(testDictInterface2);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
@ -51,6 +53,51 @@ public:
|
||||
delete f;
|
||||
}
|
||||
|
||||
void testDictInterface1()
|
||||
{
|
||||
ScopedFileCopy copy("empty", ".ogg");
|
||||
string newname = copy.fileName();
|
||||
|
||||
Vorbis::File *f = new Vorbis::File(newname.c_str());
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(uint(0), f->tag()->toDict().size());
|
||||
|
||||
TagDict newTags;
|
||||
StringList values("value 1");
|
||||
values.append("value 2");
|
||||
newTags["ARTIST"] = values;
|
||||
f->tag()->fromDict(newTags);
|
||||
|
||||
TagDict map = f->tag()->toDict();
|
||||
CPPUNIT_ASSERT_EQUAL(uint(1), map.size());
|
||||
CPPUNIT_ASSERT_EQUAL(uint(2), map["ARTIST"].size());
|
||||
CPPUNIT_ASSERT_EQUAL(String("value 1"), map["ARTIST"][0]);
|
||||
delete f;
|
||||
|
||||
}
|
||||
|
||||
void testDictInterface2()
|
||||
{
|
||||
ScopedFileCopy copy("test", ".ogg");
|
||||
string newname = copy.fileName();
|
||||
|
||||
Vorbis::File *f = new Vorbis::File(newname.c_str());
|
||||
TagDict tags = f->tag()->toDict();
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(uint(2), tags["UNUSUALTAG"].size());
|
||||
CPPUNIT_ASSERT_EQUAL(String("usual value"), tags["UNUSUALTAG"][0]);
|
||||
CPPUNIT_ASSERT_EQUAL(String("another value"), tags["UNUSUALTAG"][1]);
|
||||
CPPUNIT_ASSERT_EQUAL(String(L"öäüoΣø"), tags["UNICODETAG"][0]);
|
||||
|
||||
tags["UNICODETAG"][0] = L"νεω ναλυε";
|
||||
tags.erase("UNUSUALTAG");
|
||||
f->tag()->fromDict(tags);
|
||||
CPPUNIT_ASSERT_EQUAL(String(L"νεω ναλυε"), f->tag()->toDict()["UNICODETAG"][0]);
|
||||
CPPUNIT_ASSERT_EQUAL(false, f->tag()->toDict().contains("UNUSUALTAG"));
|
||||
|
||||
delete f;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(TestOGG);
|
||||
|
Loading…
x
Reference in New Issue
Block a user