Implement property interface for RIFF Info

This commit is contained in:
Urs Fleisch 2023-11-25 16:56:42 +01:00
parent 9233ff1f5d
commit bd06012b02
3 changed files with 165 additions and 0 deletions

View File

@ -27,6 +27,8 @@
#include <utility>
#include "tbytevector.h"
#include "tpropertymap.h"
#include "riffutils.h"
using namespace TagLib;
@ -164,6 +166,86 @@ bool RIFF::Info::Tag::isEmpty() const
return d->fieldListMap.isEmpty();
}
namespace
{
const Map<ByteVector, String> propertyKeyForId = {
{"IPRD", "ALBUM"},
{"IENG", "ARRANGER"},
{"IART", "ARTIST"},
{"IBSU", "ARTISTWEBPAGE"},
{"IBPM", "BPM"},
{"ICMT", "COMMENT"},
{"IMUS", "COMPOSER"},
{"ICOP", "COPYRIGHT"},
{"ICRD", "DATE"},
{"PRT1", "DISCSUBTITLE"},
{"ITCH", "ENCODEDBY"},
{"ISFT", "ENCODING"},
{"IDIT", "ENCODINGTIME"},
{"IGNR", "GENRE"},
{"ISRC", "ISRC"},
{"IPUB", "LABEL"},
{"ILNG", "LANGUAGE"},
{"IWRI", "LYRICIST"},
{"IMED", "MEDIA"},
{"ISTR", "PERFORMER"},
{"ICNT", "RELEASECOUNTRY"},
{"IEDT", "REMIXER"},
{"INAM", "TITLE"},
{"IPRT", "TRACKNUMBER"}
};
} // namespace
PropertyMap RIFF::Info::Tag::properties() const
{
PropertyMap props;
for(const auto &[id, value] : std::as_const(d->fieldListMap)) {
String key = propertyKeyForId.value(id);
if(!key.isEmpty()) {
props[key].append(value);
}
else {
props.addUnsupportedData(key);
}
}
return props;
}
void RIFF::Info::Tag::removeUnsupportedProperties(const StringList &props)
{
for(const auto &id : props)
d->fieldListMap.erase(id.data(String::Latin1));
}
PropertyMap RIFF::Info::Tag::setProperties(const PropertyMap &props)
{
static Map<String, ByteVector> idForPropertyKey;
if(idForPropertyKey.isEmpty()) {
for(const auto &[id, key] : propertyKeyForId) {
idForPropertyKey[key] = id;
}
}
const PropertyMap origProps = properties();
for(const auto &[key, _] : origProps) {
if(!props.contains(key) || props.value(key).isEmpty()) {
d->fieldListMap.erase(idForPropertyKey.value(key));
}
}
PropertyMap ignoredProps;
for(const auto &[key, value] : props) {
ByteVector id = idForPropertyKey.value(key);
if(!id.isEmpty() && !value.isEmpty()) {
d->fieldListMap[id] = value.front();
}
else {
ignoredProps.insert(key, value);
}
}
return ignoredProps;
}
FieldListMap RIFF::Info::Tag::fieldListMap() const
{
return d->fieldListMap;

View File

@ -130,6 +130,10 @@ namespace TagLib {
bool isEmpty() const override;
PropertyMap properties() const override;
void removeUnsupportedProperties(const StringList &props) override;
PropertyMap setProperties(const PropertyMap &props) override;
/*!
* Returns a copy of the internal fields of the tag. The returned map directly
* reflects the contents of the "INFO" chunk.

View File

@ -60,6 +60,7 @@ class TestWAV : public CppUnit::TestFixture
CPPUNIT_TEST(testPCMWithFactChunk);
CPPUNIT_TEST(testWaveFormatExtensible);
CPPUNIT_TEST(testInvalidChunk);
CPPUNIT_TEST(testRIFFInfoProperties);
CPPUNIT_TEST_SUITE_END();
public:
@ -403,6 +404,84 @@ public:
}
}
void testRIFFInfoProperties()
{
PropertyMap tags;
tags["ALBUM"] = StringList("Album");
tags["ARRANGER"] = StringList("Arranger");
tags["ARTIST"] = StringList("Artist");
tags["ARTISTWEBPAGE"] = StringList("Artist Webpage");
tags["BPM"] = StringList("123");
tags["COMMENT"] = StringList("Comment");
tags["COMPOSER"] = StringList("Composer");
tags["COPYRIGHT"] = StringList("2023 Copyright");
tags["DATE"] = StringList("2023");
tags["DISCSUBTITLE"] = StringList("Disc Subtitle");
tags["ENCODEDBY"] = StringList("Encoded by");
tags["ENCODING"] = StringList("Encoding");
tags["ENCODINGTIME"] = StringList("2023-11-25 15:42:39");
tags["GENRE"] = StringList("Genre");
tags["ISRC"] = StringList("UKAAA0500001");
tags["LABEL"] = StringList("Label");
tags["LANGUAGE"] = StringList("eng");
tags["LYRICIST"] = StringList("Lyricist");
tags["MEDIA"] = StringList("Media");
tags["PERFORMER"] = StringList("Performer");
tags["RELEASECOUNTRY"] = StringList("Release Country");
tags["REMIXER"] = StringList("Remixer");
tags["TITLE"] = StringList("Title");
tags["TRACKNUMBER"] = StringList("2/4");
ScopedFileCopy copy("empty", ".wav");
{
RIFF::WAV::File f(copy.fileName().c_str());
RIFF::Info::Tag *infoTag = f.InfoTag();
CPPUNIT_ASSERT(infoTag->isEmpty());
PropertyMap properties = infoTag->properties();
CPPUNIT_ASSERT(properties.isEmpty());
infoTag->setProperties(tags);
f.save();
}
{
const RIFF::WAV::File f(copy.fileName().c_str());
RIFF::Info::Tag *infoTag = f.InfoTag();
CPPUNIT_ASSERT(!infoTag->isEmpty());
PropertyMap properties = infoTag->properties();
if (tags != properties) {
CPPUNIT_ASSERT_EQUAL(tags.toString(), properties.toString());
}
CPPUNIT_ASSERT(tags == properties);
const RIFF::Info::FieldListMap expectedFields = {
{"IPRD", "Album"},
{"IENG", "Arranger"},
{"IART", "Artist"},
{"IBSU", "Artist Webpage"},
{"IBPM", "123"},
{"ICMT", "Comment"},
{"IMUS", "Composer"},
{"ICOP", "2023 Copyright"},
{"ICRD", "2023"},
{"PRT1", "Disc Subtitle"},
{"ITCH", "Encoded by"},
{"ISFT", "Encoding"},
{"IDIT", "2023-11-25 15:42:39"},
{"IGNR", "Genre"},
{"ISRC", "UKAAA0500001"},
{"IPUB", "Label"},
{"ILNG", "eng"},
{"IWRI", "Lyricist"},
{"IMED", "Media"},
{"ISTR", "Performer"},
{"ICNT", "Release Country"},
{"IEDT", "Remixer"},
{"INAM", "Title"},
{"IPRT", "2/4"}
};
CPPUNIT_ASSERT(expectedFields == infoTag->fieldListMap());
}
}
};
CPPUNIT_TEST_SUITE_REGISTRATION(TestWAV);