Restructure FieldMapBasedTag to use CRTP

This commit is contained in:
Martchus 2017-03-07 00:02:59 +01:00
parent 11d881a41e
commit 138fa32f29
11 changed files with 181 additions and 167 deletions

View File

@ -8,6 +8,16 @@
namespace Media { namespace Media {
/*!
* \class Media::FieldMapBasedTagTraits
* \brief Defines traits for the specified \a ImplementationType.
*
* A template specialization for each FieldMapBasedTag subclass must be provided.
*/
template<typename ImplementationType>
class FieldMapBasedTagTraits
{};
/*! /*!
* \class Media::FieldMapBasedTag * \class Media::FieldMapBasedTag
* \brief The FieldMapBasedTag provides a generic implementation of Tag which stores * \brief The FieldMapBasedTag provides a generic implementation of Tag which stores
@ -21,38 +31,46 @@ namespace Media {
* *
* \tparam Compare Specifies the key comparsion function. Default is std::less. * \tparam Compare Specifies the key comparsion function. Default is std::less.
*/ */
template <class FieldType, class Compare = std::less<typename FieldType::identifierType> > template <class ImplementationType>
class FieldMapBasedTag : public Tag class FieldMapBasedTag : public Tag
{ {
public: public:
friend class FieldMapBasedTagTraits<ImplementationType>;
typedef typename FieldMapBasedTagTraits<ImplementationType>::implementationType implementationType;
typedef typename FieldMapBasedTagTraits<ImplementationType>::fieldType fieldType;
typedef typename FieldMapBasedTagTraits<ImplementationType>::fieldType::identifierType identifierType;
typedef typename FieldMapBasedTagTraits<ImplementationType>::compare compare;
FieldMapBasedTag(); FieldMapBasedTag();
virtual const TagValue &value(const typename FieldType::identifierType &id) const; // FIXME: use static polymorphism TagType type() const;
const char *typeName() const;
TagTextEncoding proposedTextEncoding() const;
virtual const TagValue &value(const identifierType &id) const; // FIXME: use static polymorphism
const TagValue &value(KnownField field) const; const TagValue &value(KnownField field) const;
std::vector<const TagValue *> values(const typename FieldType::identifierType &id) const; std::vector<const TagValue *> values(const identifierType &id) const;
std::vector<const TagValue *> values(KnownField field) const; std::vector<const TagValue *> values(KnownField field) const;
virtual bool setValue(const typename FieldType::identifierType &id, const TagValue &value); // FIXME: use static polymorphism virtual bool setValue(const identifierType &id, const TagValue &value); // FIXME: use static polymorphism
bool setValue(KnownField field, const TagValue &value); bool setValue(KnownField field, const TagValue &value);
bool setValues(const typename FieldType::identifierType &id, const std::vector<TagValue> &values); bool setValues(const identifierType &id, const std::vector<TagValue> &values);
bool setValues(KnownField field, const std::vector<TagValue> &values); bool setValues(KnownField field, const std::vector<TagValue> &values);
bool hasField(KnownField field) const; bool hasField(KnownField field) const;
virtual bool hasField(const typename FieldType::identifierType &id) const; // FIXME: use static polymorphism virtual bool hasField(const identifierType &id) const; // FIXME: use static polymorphism
void removeAllFields(); void removeAllFields();
const std::multimap<typename FieldType::identifierType, FieldType, Compare> &fields() const; const std::multimap<identifierType, fieldType, compare> &fields() const;
std::multimap<typename FieldType::identifierType, FieldType, Compare> &fields(); std::multimap<identifierType, fieldType, compare> &fields();
unsigned int fieldCount() const; unsigned int fieldCount() const;
virtual typename FieldType::identifierType fieldId(KnownField value) const = 0; // FIXME: use static polymorphism virtual identifierType fieldId(KnownField value) const = 0; // FIXME: use static polymorphism
virtual KnownField knownField(const typename FieldType::identifierType &id) const = 0; // FIXME: use static polymorphism virtual KnownField knownField(const identifierType &id) const = 0; // FIXME: use static polymorphism
bool supportsField(KnownField field) const; bool supportsField(KnownField field) const;
using Tag::proposedDataType; using Tag::proposedDataType;
virtual TagDataType proposedDataType(const typename FieldType::identifierType &id) const; // FIXME: use static polymorphism virtual TagDataType proposedDataType(const identifierType &id) const; // FIXME: use static polymorphism
int insertFields(const FieldMapBasedTag<FieldType, Compare> &from, bool overwrite); int insertFields(const FieldMapBasedTag<ImplementationType> &from, bool overwrite);
unsigned int insertValues(const Tag &from, bool overwrite); unsigned int insertValues(const Tag &from, bool overwrite);
void ensureTextValuesAreProperlyEncoded(); void ensureTextValuesAreProperlyEncoded();
typedef FieldType fieldType;
private: private:
std::multimap<typename FieldType::identifierType, FieldType, Compare> m_fields; std::multimap<identifierType, fieldType, compare> m_fields;
}; };
/*! /*!
@ -72,23 +90,41 @@ private:
/*! /*!
* \brief Constructs a new FieldMapBasedTag. * \brief Constructs a new FieldMapBasedTag.
*/ */
template <class FieldType, class Compare> template <class ImplementationType>
FieldMapBasedTag<FieldType, Compare>::FieldMapBasedTag() FieldMapBasedTag<ImplementationType>::FieldMapBasedTag()
{} {}
template <class ImplementationType>
TagType FieldMapBasedTag<ImplementationType>::type() const
{
return ImplementationType::tagType;
}
template <class ImplementationType>
const char *FieldMapBasedTag<ImplementationType>::typeName() const
{
return ImplementationType::tagName;
}
template<class ImplementationType>
TagTextEncoding FieldMapBasedTag<ImplementationType>::proposedTextEncoding() const
{
return ImplementationType::defaultTextEncoding;
}
/*! /*!
* \brief Returns the value of the field with the specified \a id. * \brief Returns the value of the field with the specified \a id.
* \sa Tag::value() * \sa Tag::value()
*/ */
template <class FieldType, class Compare> template <class ImplementationType>
inline const TagValue &FieldMapBasedTag<FieldType, Compare>::value(const typename FieldType::identifierType &id) const inline const TagValue &FieldMapBasedTag<ImplementationType>::value(const identifierType &id) const
{ {
auto i = m_fields.find(id); auto i = m_fields.find(id);
return i != m_fields.end() ? i->second.value() : TagValue::empty(); return i != m_fields.end() ? i->second.value() : TagValue::empty();
} }
template <class FieldType, class Compare> template <class ImplementationType>
inline const TagValue &FieldMapBasedTag<FieldType, Compare>::value(KnownField field) const inline const TagValue &FieldMapBasedTag<ImplementationType>::value(KnownField field) const
{ {
return value(fieldId(field)); return value(fieldId(field));
} }
@ -97,8 +133,8 @@ inline const TagValue &FieldMapBasedTag<FieldType, Compare>::value(KnownField fi
* \brief Returns the values of the field with the specified \a id. * \brief Returns the values of the field with the specified \a id.
* \sa Tag::values() * \sa Tag::values()
*/ */
template <class FieldType, class Compare> template <class ImplementationType>
inline std::vector<const TagValue *> FieldMapBasedTag<FieldType, Compare>::values(const typename FieldType::identifierType &id) const inline std::vector<const TagValue *> FieldMapBasedTag<ImplementationType>::values(const identifierType &id) const
{ {
auto range = m_fields.equal_range(id); auto range = m_fields.equal_range(id);
std::vector<const TagValue *> values; std::vector<const TagValue *> values;
@ -110,14 +146,14 @@ inline std::vector<const TagValue *> FieldMapBasedTag<FieldType, Compare>::value
return values; return values;
} }
template <class FieldType, class Compare> template <class ImplementationType>
inline std::vector<const TagValue *> FieldMapBasedTag<FieldType, Compare>::values(KnownField field) const inline std::vector<const TagValue *> FieldMapBasedTag<ImplementationType>::values(KnownField field) const
{ {
return values(fieldId(field)); return values(fieldId(field));
} }
template <class FieldType, class Compare> template <class ImplementationType>
inline bool FieldMapBasedTag<FieldType, Compare>::setValue(KnownField field, const TagValue &value) inline bool FieldMapBasedTag<ImplementationType>::setValue(KnownField field, const TagValue &value)
{ {
return setValue(fieldId(field), value); return setValue(fieldId(field), value);
} }
@ -126,14 +162,14 @@ inline bool FieldMapBasedTag<FieldType, Compare>::setValue(KnownField field, con
* \brief Assigns the given \a value to the field with the specified \a id. * \brief Assigns the given \a value to the field with the specified \a id.
* \sa Tag::setValue() * \sa Tag::setValue()
*/ */
template <class FieldType, class Compare> template <class ImplementationType>
bool FieldMapBasedTag<FieldType, Compare>::setValue(const typename FieldType::identifierType &id, const Media::TagValue &value) bool FieldMapBasedTag<ImplementationType>::setValue(const identifierType &id, const Media::TagValue &value)
{ {
auto i = m_fields.find(id); auto i = m_fields.find(id);
if(i != m_fields.end()) { // field already exists -> set its value if(i != m_fields.end()) { // field already exists -> set its value
i->second.setValue(value); i->second.setValue(value);
} else if(!value.isEmpty()) { // field doesn't exist -> create new one if value is not null } else if(!value.isEmpty()) { // field doesn't exist -> create new one if value is not null
m_fields.insert(std::make_pair(id, FieldType(id, value))); m_fields.insert(std::make_pair(id, fieldType(id, value)));
} else { // otherwise return false } else { // otherwise return false
return false; return false;
} }
@ -146,8 +182,8 @@ bool FieldMapBasedTag<FieldType, Compare>::setValue(const typename FieldType::id
* method will replace all currently assigned values with the specified \a values. * method will replace all currently assigned values with the specified \a values.
* \sa Tag::setValues() * \sa Tag::setValues()
*/ */
template <class FieldType, class Compare> template <class ImplementationType>
bool FieldMapBasedTag<FieldType, Compare>::setValues(const typename FieldType::identifierType &id, const std::vector<TagValue> &values) bool FieldMapBasedTag<ImplementationType>::setValues(const identifierType &id, const std::vector<TagValue> &values)
{ {
auto valuesIterator = values.cbegin(); auto valuesIterator = values.cbegin();
auto range = m_fields.equal_range(id); auto range = m_fields.equal_range(id);
@ -161,7 +197,7 @@ bool FieldMapBasedTag<FieldType, Compare>::setValues(const typename FieldType::i
} }
// add remaining specified values (there are more specified values than existing ones) // add remaining specified values (there are more specified values than existing ones)
for(; valuesIterator != values.cend(); ++valuesIterator) { for(; valuesIterator != values.cend(); ++valuesIterator) {
m_fields.insert(std::make_pair(id, FieldType(id, *valuesIterator))); m_fields.insert(std::make_pair(id, fieldType(id, *valuesIterator)));
} }
// remove remaining existing values (there are more existing values than specified ones) // remove remaining existing values (there are more existing values than specified ones)
for(; range.first != range.second; ++range.first) { for(; range.first != range.second; ++range.first) {
@ -176,14 +212,14 @@ bool FieldMapBasedTag<FieldType, Compare>::setValues(const typename FieldType::i
* method will replace all currently assigned values with the specified \a values. * method will replace all currently assigned values with the specified \a values.
* \sa Tag::setValues() * \sa Tag::setValues()
*/ */
template <class FieldType, class Compare> template <class ImplementationType>
bool FieldMapBasedTag<FieldType, Compare>::setValues(KnownField field, const std::vector<TagValue> &values) bool FieldMapBasedTag<ImplementationType>::setValues(KnownField field, const std::vector<TagValue> &values)
{ {
return setValues(fieldId(field), values); return setValues(fieldId(field), values);
} }
template <class FieldType, class Compare> template <class ImplementationType>
inline bool FieldMapBasedTag<FieldType, Compare>::hasField(KnownField field) const inline bool FieldMapBasedTag<ImplementationType>::hasField(KnownField field) const
{ {
return hasField(fieldId(field)); return hasField(fieldId(field));
} }
@ -191,8 +227,8 @@ inline bool FieldMapBasedTag<FieldType, Compare>::hasField(KnownField field) con
/*! /*!
* \brief Returns an indication whether the field with the specified \a id is present. * \brief Returns an indication whether the field with the specified \a id is present.
*/ */
template <class FieldType, class Compare> template <class ImplementationType>
inline bool FieldMapBasedTag<FieldType, Compare>::hasField(const typename FieldType::identifierType &id) const inline bool FieldMapBasedTag<ImplementationType>::hasField(const identifierType &id) const
{ {
for (auto range = m_fields.equal_range(id); range.first != range.second; ++range.first) { for (auto range = m_fields.equal_range(id); range.first != range.second; ++range.first) {
if(!range.first->second.value().isEmpty()) { if(!range.first->second.value().isEmpty()) {
@ -202,8 +238,8 @@ inline bool FieldMapBasedTag<FieldType, Compare>::hasField(const typename FieldT
return false; return false;
} }
template <class FieldType, class Compare> template <class ImplementationType>
inline void FieldMapBasedTag<FieldType, Compare>::removeAllFields() inline void FieldMapBasedTag<ImplementationType>::removeAllFields()
{ {
m_fields.clear(); m_fields.clear();
} }
@ -211,8 +247,8 @@ inline void FieldMapBasedTag<FieldType, Compare>::removeAllFields()
/*! /*!
* \brief Returns the fields of the tag by providing direct access to the field map of the tag. * \brief Returns the fields of the tag by providing direct access to the field map of the tag.
*/ */
template <class FieldType, class Compare> template <class ImplementationType>
inline const std::multimap<typename FieldType::identifierType, FieldType, Compare> &FieldMapBasedTag<FieldType, Compare>::fields() const inline auto FieldMapBasedTag<ImplementationType>::fields() const -> const std::multimap<identifierType, fieldType, compare> &
{ {
return m_fields; return m_fields;
} }
@ -220,14 +256,14 @@ inline const std::multimap<typename FieldType::identifierType, FieldType, Compar
/*! /*!
* \brief Returns the fields of the tag by providing direct access to the field map of the tag. * \brief Returns the fields of the tag by providing direct access to the field map of the tag.
*/ */
template <class FieldType, class Compare> template <class ImplementationType>
inline std::multimap<typename FieldType::identifierType, FieldType, Compare> &FieldMapBasedTag<FieldType, Compare>::fields() inline auto FieldMapBasedTag<ImplementationType>::fields() -> std::multimap<identifierType, fieldType, compare> &
{ {
return m_fields; return m_fields;
} }
template <class FieldType, class Compare> template <class ImplementationType>
unsigned int FieldMapBasedTag<FieldType, Compare>::fieldCount() const unsigned int FieldMapBasedTag<ImplementationType>::fieldCount() const
{ {
unsigned int count = 0; unsigned int count = 0;
for(const auto &field : m_fields) { for(const auto &field : m_fields) {
@ -238,18 +274,18 @@ unsigned int FieldMapBasedTag<FieldType, Compare>::fieldCount() const
return count; return count;
} }
template <class FieldType, class Compare> template <class ImplementationType>
inline bool FieldMapBasedTag<FieldType, Compare>::supportsField(KnownField field) const inline bool FieldMapBasedTag<ImplementationType>::supportsField(KnownField field) const
{ {
static typename FieldType::identifierType def; static identifierType def;
return fieldId(field) != def; return fieldId(field) != def;
} }
/*! /*!
* \brief Returns the proposed data type for the field with the specified \a id. * \brief Returns the proposed data type for the field with the specified \a id.
*/ */
template <class FieldType, class Compare> template <class ImplementationType>
inline TagDataType FieldMapBasedTag<FieldType, Compare>::proposedDataType(const typename FieldType::identifierType &id) const inline TagDataType FieldMapBasedTag<ImplementationType>::proposedDataType(const identifierType &id) const
{ {
return Tag::proposedDataType(knownField(id)); return Tag::proposedDataType(knownField(id));
} }
@ -260,18 +296,18 @@ inline TagDataType FieldMapBasedTag<FieldType, Compare>::proposedDataType(const
* \param overwrite Indicates whether existing fields should be overwritten. * \param overwrite Indicates whether existing fields should be overwritten.
* \return Returns the number of fields that have been inserted. * \return Returns the number of fields that have been inserted.
*/ */
template <class FieldType, class Compare> template <class ImplementationType>
int FieldMapBasedTag<FieldType, Compare>::insertFields(const FieldMapBasedTag<FieldType, Compare> &from, bool overwrite) int FieldMapBasedTag<ImplementationType>::insertFields(const FieldMapBasedTag<ImplementationType> &from, bool overwrite)
{ {
int fieldsInserted = 0; int fieldsInserted = 0;
for(const auto &pair : from.fields()) { for(const auto &pair : from.fields()) {
const FieldType &fromField = pair.second; const fieldType &fromField = pair.second;
if(fromField.value().isEmpty()) if(fromField.value().isEmpty())
continue; continue;
bool fieldInserted = false; bool fieldInserted = false;
auto range = fields().equal_range(fromField.id()); auto range = fields().equal_range(fromField.id());
for(auto i = range.first; i != range.second; ++i) { for(auto i = range.first; i != range.second; ++i) {
FieldType &ownField = i->second; fieldType &ownField = i->second;
if((fromField.isTypeInfoAssigned() && ownField.isTypeInfoAssigned() if((fromField.isTypeInfoAssigned() && ownField.isTypeInfoAssigned()
&& fromField.typeInfo() == ownField.typeInfo()) && fromField.typeInfo() == ownField.typeInfo())
|| (!fromField.isTypeInfoAssigned() && ! ownField.isTypeInfoAssigned())) { || (!fromField.isTypeInfoAssigned() && ! ownField.isTypeInfoAssigned())) {
@ -291,19 +327,19 @@ int FieldMapBasedTag<FieldType, Compare>::insertFields(const FieldMapBasedTag<Fi
return fieldsInserted; return fieldsInserted;
} }
template <class FieldType, class Compare> template <class ImplementationType>
unsigned int FieldMapBasedTag<FieldType, Compare>::insertValues(const Tag &from, bool overwrite) unsigned int FieldMapBasedTag<ImplementationType>::insertValues(const Tag &from, bool overwrite)
{ {
if(type() == from.type()) { if(type() == from.type()) {
// the tags are of the same type, we can insert the fields directly // the tags are of the same type, we can insert the fields directly
return insertFields(static_cast<const FieldMapBasedTag<FieldType, Compare> &>(from), overwrite); return insertFields(static_cast<const FieldMapBasedTag<ImplementationType> &>(from), overwrite);
} else { } else {
return Tag::insertValues(from, overwrite); return Tag::insertValues(from, overwrite);
} }
} }
template <class FieldType, class Compare> template <class ImplementationType>
void FieldMapBasedTag<FieldType, Compare>::ensureTextValuesAreProperlyEncoded() void FieldMapBasedTag<ImplementationType>::ensureTextValuesAreProperlyEncoded()
{ {
for(auto &field : fields()) { for(auto &field : fields()) {
field.second.value().convertDataEncodingForTag(this); field.second.value().convertDataEncodingForTag(this);

View File

@ -12,7 +12,7 @@ class TagField;
* \class Media::TagFieldTraits * \class Media::TagFieldTraits
* \brief Defines traits for the specified \a ImplementationType. * \brief Defines traits for the specified \a ImplementationType.
* *
* A template specialization for each TagField derivat must be provided. * A template specialization for each TagField subclass must be provided.
*/ */
template<typename ImplementationType> template<typename ImplementationType>
class TagFieldTraits class TagFieldTraits

View File

@ -30,7 +30,7 @@ TagType Id3v1Tag::type() const
const char *Id3v1Tag::typeName() const const char *Id3v1Tag::typeName() const
{ {
return "ID3v1 tag"; return tagName;
} }
bool Id3v1Tag::canEncodingBeUsed(TagTextEncoding encoding) const bool Id3v1Tag::canEncodingBeUsed(TagTextEncoding encoding) const

View File

@ -12,6 +12,7 @@ public:
Id3v1Tag(); Id3v1Tag();
static constexpr TagType tagType = TagType::Id3v1Tag; static constexpr TagType tagType = TagType::Id3v1Tag;
static constexpr const char *tagName = "ID3v1 tag";
TagType type() const; TagType type() const;
const char *typeName() const; const char *typeName() const;
bool canEncodingBeUsed(TagTextEncoding encoding) const; bool canEncodingBeUsed(TagTextEncoding encoding) const;

View File

@ -147,16 +147,6 @@ TagDataType Id3v2Tag::proposedDataType(const uint32 &id) const
} }
} }
const TagValue &Id3v2Tag::value(const typename Id3v2Frame::identifierType &id) const
{
return FieldMapBasedTag<Id3v2Frame, FrameComparer>::value(id);
}
bool Id3v2Tag::setValue(const typename Id3v2Frame::identifierType &id, const TagValue &value)
{
return FieldMapBasedTag<Id3v2Frame, FrameComparer>::setValue(id, value);
}
/*! /*!
* \brief Parses tag information from the specified \a stream. * \brief Parses tag information from the specified \a stream.
* *

View File

@ -52,23 +52,33 @@ inline uint64 Id3v2TagMaker::requiredSize() const
return m_requiredSize; return m_requiredSize;
} }
class TAG_PARSER_EXPORT Id3v2Tag : public FieldMapBasedTag<Id3v2Frame, FrameComparer> /*!
* \brief Defines traits for the TagField implementation of the Id3v2Tag class.
*/
template <>
class TAG_PARSER_EXPORT FieldMapBasedTagTraits<Id3v2Tag>
{
public:
typedef Id3v2Tag implementationType;
typedef Id3v2Frame fieldType;
typedef FrameComparer compare;
};
class TAG_PARSER_EXPORT Id3v2Tag : public FieldMapBasedTag<Id3v2Tag>
{ {
public: public:
Id3v2Tag(); Id3v2Tag();
static constexpr TagType tagType = TagType::Id3v2Tag; static constexpr TagType tagType = TagType::Id3v2Tag;
TagType type() const; static constexpr const char *tagName = "ID3v2 tag";
const char *typeName() const; static constexpr TagTextEncoding defaultTextEncoding = TagTextEncoding::Utf16LittleEndian;
TagTextEncoding proposedTextEncoding() const; TagTextEncoding proposedTextEncoding() const;
bool canEncodingBeUsed(TagTextEncoding encoding) const; bool canEncodingBeUsed(TagTextEncoding encoding) const;
uint32 fieldId(KnownField value) const; uint32 fieldId(KnownField value) const;
KnownField knownField(const uint32 &id) const; KnownField knownField(const uint32 &id) const;
TagDataType proposedDataType(const uint32 &id) const; TagDataType proposedDataType(const uint32 &id) const;
using FieldMapBasedTag<Id3v2Frame, FrameComparer>::value; using FieldMapBasedTag<Id3v2Tag>::value;
const TagValue &value(const typename Id3v2Frame::identifierType &id) const; using FieldMapBasedTag<Id3v2Tag>::setValue;
using FieldMapBasedTag<Id3v2Frame, FrameComparer>::setValue;
bool setValue(const typename Id3v2Frame::identifierType &id, const TagValue &value);
bool supportsDescription(KnownField field) const; bool supportsDescription(KnownField field) const;
bool supportsMimeType(KnownField field) const; bool supportsMimeType(KnownField field) const;
@ -109,16 +119,6 @@ inline Id3v2Tag::Id3v2Tag() :
m_paddingSize(0) m_paddingSize(0)
{} {}
inline TagType Id3v2Tag::type() const
{
return TagType::Id3v2Tag;
}
inline const char *Id3v2Tag::typeName() const
{
return "ID3v2 tag";
}
inline TagTextEncoding Id3v2Tag::proposedTextEncoding() const inline TagTextEncoding Id3v2Tag::proposedTextEncoding() const
{ {
return m_majorVersion > 3 ? TagTextEncoding::Utf8 : TagTextEncoding::Utf16LittleEndian; return m_majorVersion > 3 ? TagTextEncoding::Utf8 : TagTextEncoding::Utf16LittleEndian;

View File

@ -47,16 +47,26 @@ inline uint64 MatroskaTagMaker::requiredSize() const
return m_totalSize; return m_totalSize;
} }
class TAG_PARSER_EXPORT MatroskaTag : public FieldMapBasedTag<MatroskaTagField> /*!
* \brief Defines traits for the TagField implementation of the MatroskaTag class.
*/
template <>
class TAG_PARSER_EXPORT FieldMapBasedTagTraits<MatroskaTag>
{
public:
typedef MatroskaTag implementationType;
typedef MatroskaTagField fieldType;
typedef std::less<typename fieldType::identifierType> compare;
};
class TAG_PARSER_EXPORT MatroskaTag : public FieldMapBasedTag<MatroskaTag>
{ {
public: public:
MatroskaTag(); MatroskaTag();
static constexpr TagType tagType = TagType::MatroskaTag; static constexpr TagType tagType = TagType::MatroskaTag;
// FIXME: implement type() and typeName() in FieldMapBasedTag static constexpr const char *tagName = "Matroska tag";
TagType type() const; static constexpr TagTextEncoding defaultTextEncoding = TagTextEncoding::Utf8;
const char *typeName() const;
TagTextEncoding proposedTextEncoding() const;
bool canEncodingBeUsed(TagTextEncoding encoding) const; bool canEncodingBeUsed(TagTextEncoding encoding) const;
bool supportsTarget() const; bool supportsTarget() const;
TagTargetLevel targetLevel() const; TagTargetLevel targetLevel() const;
@ -88,21 +98,6 @@ inline TagTargetLevel MatroskaTag::targetLevel() const
return matroskaTagTargetLevel(m_target.level()); return matroskaTagTargetLevel(m_target.level());
} }
inline TagType MatroskaTag::type() const
{
return TagType::MatroskaTag;
}
inline const char *MatroskaTag::typeName() const
{
return "Matroska tag";
}
inline TagTextEncoding MatroskaTag::proposedTextEncoding() const
{
return TagTextEncoding::Utf8;
}
inline bool MatroskaTag::canEncodingBeUsed(TagTextEncoding encoding) const inline bool MatroskaTag::canEncodingBeUsed(TagTextEncoding encoding) const
{ {
return encoding == TagTextEncoding::Utf8; return encoding == TagTextEncoding::Utf8;

View File

@ -59,16 +59,16 @@ const TagValue &Mp4Tag::value(KnownField field) const
{ {
switch(field) { switch(field) {
case KnownField::Genre: { case KnownField::Genre: {
const TagValue &value = FieldMapBasedTag<fieldType>::value(Mp4TagAtomIds::Genre); const TagValue &value = FieldMapBasedTag<Mp4Tag>::value(Mp4TagAtomIds::Genre);
if(!value.isEmpty()) { if(!value.isEmpty()) {
return value; return value;
} else { } else {
return FieldMapBasedTag<fieldType>::value(Mp4TagAtomIds::PreDefinedGenre); return FieldMapBasedTag<Mp4Tag>::value(Mp4TagAtomIds::PreDefinedGenre);
} }
} case KnownField::EncoderSettings: } case KnownField::EncoderSettings:
return this->value(Mp4TagExtendedMeanIds::iTunes, Mp4TagExtendedNameIds::cdec); return this->value(Mp4TagExtendedMeanIds::iTunes, Mp4TagExtendedNameIds::cdec);
case KnownField::RecordLabel: { case KnownField::RecordLabel: {
const TagValue &value = FieldMapBasedTag<fieldType>::value(Mp4TagAtomIds::RecordLabel); const TagValue &value = FieldMapBasedTag<Mp4Tag>::value(Mp4TagAtomIds::RecordLabel);
if(!value.isEmpty()) { if(!value.isEmpty()) {
return value; return value;
} else { } else {
@ -76,13 +76,13 @@ const TagValue &Mp4Tag::value(KnownField field) const
} }
} }
default: default:
return FieldMapBasedTag<fieldType>::value(field); return FieldMapBasedTag<Mp4Tag>::value(field);
} }
} }
std::vector<const TagValue *> Mp4Tag::values(KnownField field) const std::vector<const TagValue *> Mp4Tag::values(KnownField field) const
{ {
auto values = FieldMapBasedTag<fieldType>::values(field); auto values = FieldMapBasedTag<Mp4Tag>::values(field);
const Mp4ExtendedFieldId extendedId(field); const Mp4ExtendedFieldId extendedId(field);
if(extendedId) { if(extendedId) {
auto range = fields().equal_range(Mp4TagAtomIds::Extended); auto range = fields().equal_range(Mp4TagAtomIds::Extended);
@ -180,10 +180,10 @@ bool Mp4Tag::setValue(KnownField field, const TagValue &value)
switch(value.type()) { switch(value.type()) {
case TagDataType::StandardGenreIndex: case TagDataType::StandardGenreIndex:
fields().erase(Mp4TagAtomIds::Genre); fields().erase(Mp4TagAtomIds::Genre);
return FieldMapBasedTag<fieldType>::setValue(Mp4TagAtomIds::PreDefinedGenre, value); return FieldMapBasedTag<Mp4Tag>::setValue(Mp4TagAtomIds::PreDefinedGenre, value);
default: default:
fields().erase(Mp4TagAtomIds::PreDefinedGenre); fields().erase(Mp4TagAtomIds::PreDefinedGenre);
return FieldMapBasedTag<fieldType>::setValue(Mp4TagAtomIds::Genre, value); return FieldMapBasedTag<Mp4Tag>::setValue(Mp4TagAtomIds::Genre, value);
} }
case KnownField::EncoderSettings: case KnownField::EncoderSettings:
return setValue(Mp4TagExtendedMeanIds::iTunes, Mp4TagExtendedNameIds::cdec, value); return setValue(Mp4TagExtendedMeanIds::iTunes, Mp4TagExtendedNameIds::cdec, value);
@ -193,7 +193,7 @@ bool Mp4Tag::setValue(KnownField field, const TagValue &value)
} }
FALLTHROUGH; FALLTHROUGH;
default: default:
return FieldMapBasedTag<fieldType>::setValue(field, value); return FieldMapBasedTag<Mp4Tag>::setValue(field, value);
} }
} }
@ -225,7 +225,7 @@ bool Mp4Tag::setValues(KnownField field, const std::vector<TagValue> &values)
range.first->second.setValue(TagValue()); range.first->second.setValue(TagValue());
} }
} }
return FieldMapBasedTag<fieldType>::setValues(field, values); return FieldMapBasedTag<Mp4Tag>::setValues(field, values);
} }
/*! /*!
@ -260,10 +260,10 @@ bool Mp4Tag::hasField(KnownField field) const
{ {
switch(field) { switch(field) {
case KnownField::Genre: case KnownField::Genre:
return FieldMapBasedTag<fieldType>::hasField(Mp4TagAtomIds::PreDefinedGenre) return FieldMapBasedTag<Mp4Tag>::hasField(Mp4TagAtomIds::PreDefinedGenre)
|| FieldMapBasedTag<fieldType>::hasField(Mp4TagAtomIds::Genre); || FieldMapBasedTag<Mp4Tag>::hasField(Mp4TagAtomIds::Genre);
default: default:
return FieldMapBasedTag<fieldType>::hasField(field); return FieldMapBasedTag<Mp4Tag>::hasField(field);
} }
} }

View File

@ -87,39 +87,50 @@ inline uint64 Mp4TagMaker::requiredSize() const
return m_metaSize; return m_metaSize;
} }
class TAG_PARSER_EXPORT Mp4Tag : public FieldMapBasedTag<Mp4TagField> /*!
* \brief Defines traits for the TagField implementation of the Mp4Tag class.
*/
template <>
class TAG_PARSER_EXPORT FieldMapBasedTagTraits<Mp4Tag>
{
public:
typedef Mp4Tag implementationType;
typedef Mp4TagField fieldType;
typedef std::less<typename fieldType::identifierType> compare;
};
class TAG_PARSER_EXPORT Mp4Tag : public FieldMapBasedTag<Mp4Tag>
{ {
public: public:
Mp4Tag(); Mp4Tag();
static constexpr TagType tagType = TagType::Mp4Tag; static constexpr TagType tagType = TagType::Mp4Tag;
TagType type() const; static constexpr const char *tagName = "MP4/iTunes tag";
const char *typeName() const; static constexpr TagTextEncoding defaultTextEncoding = TagTextEncoding::Utf8;
TagTextEncoding proposedTextEncoding() const;
bool canEncodingBeUsed(TagTextEncoding encoding) const; bool canEncodingBeUsed(TagTextEncoding encoding) const;
uint32 fieldId(KnownField field) const; uint32 fieldId(KnownField field) const;
KnownField knownField(const uint32 &id) const; KnownField knownField(const uint32 &id) const;
bool supportsField(KnownField field) const; bool supportsField(KnownField field) const;
using FieldMapBasedTag<Mp4TagField>::value; using FieldMapBasedTag<Mp4Tag>::value;
const TagValue &value(KnownField value) const; const TagValue &value(KnownField value) const;
using FieldMapBasedTag<Mp4TagField>::values; using FieldMapBasedTag<Mp4Tag>::values;
std::vector<const TagValue *> values(KnownField field) const; std::vector<const TagValue *> values(KnownField field) const;
#ifdef LEGACY_API #ifdef LEGACY_API
const TagValue &value(const std::string mean, const std::string name) const; const TagValue &value(const std::string mean, const std::string name) const;
#endif #endif
const TagValue &value(const std::string &mean, const std::string &name) const; const TagValue &value(const std::string &mean, const std::string &name) const;
const TagValue &value(const char *mean, const char *name) const; const TagValue &value(const char *mean, const char *name) const;
using FieldMapBasedTag<Mp4TagField>::setValue; using FieldMapBasedTag<Mp4Tag>::setValue;
bool setValue(KnownField field, const TagValue &value); bool setValue(KnownField field, const TagValue &value);
using FieldMapBasedTag<Mp4TagField>::setValues; using FieldMapBasedTag<Mp4Tag>::setValues;
bool setValues(KnownField field, const std::vector<TagValue> &values); bool setValues(KnownField field, const std::vector<TagValue> &values);
#ifdef LEGACY_API #ifdef LEGACY_API
bool setValue(const std::string mean, const std::string name, const TagValue &value); bool setValue(const std::string mean, const std::string name, const TagValue &value);
#endif #endif
bool setValue(const std::string &mean, const std::string &name, const TagValue &value); bool setValue(const std::string &mean, const std::string &name, const TagValue &value);
bool setValue(const char *mean, const char *name, const TagValue &value); bool setValue(const char *mean, const char *name, const TagValue &value);
using FieldMapBasedTag<Mp4TagField>::hasField; using FieldMapBasedTag<Mp4Tag>::hasField;
bool hasField(KnownField value) const; bool hasField(KnownField value) const;
void parse(Mp4Atom &metaAtom); void parse(Mp4Atom &metaAtom);
@ -133,28 +144,13 @@ public:
inline Mp4Tag::Mp4Tag() inline Mp4Tag::Mp4Tag()
{} {}
inline TagType Mp4Tag::type() const
{
return TagType::Mp4Tag;
}
inline const char *Mp4Tag::typeName() const
{
return "MP4/iTunes tag";
}
inline TagTextEncoding Mp4Tag::proposedTextEncoding() const
{
return TagTextEncoding::Utf8;
}
inline bool Mp4Tag::supportsField(KnownField field) const inline bool Mp4Tag::supportsField(KnownField field) const
{ {
switch(field) { switch(field) {
case KnownField::EncoderSettings: case KnownField::EncoderSettings:
return true; return true;
default: default:
return FieldMapBasedTag<Mp4TagField>::supportsField(field); return FieldMapBasedTag<Mp4Tag>::supportsField(field);
} }
} }

View File

@ -29,7 +29,7 @@ const TagValue &VorbisComment::value(KnownField field) const
case KnownField::Vendor: case KnownField::Vendor:
return vendor(); return vendor();
default: default:
return FieldMapBasedTag<VorbisCommentField, CaseInsensitiveStringComparer>::value(field); return FieldMapBasedTag<VorbisComment>::value(field);
} }
} }
@ -40,7 +40,7 @@ bool VorbisComment::setValue(KnownField field, const TagValue &value)
setVendor(value); setVendor(value);
return true; return true;
default: default:
return FieldMapBasedTag<VorbisCommentField, CaseInsensitiveStringComparer>::setValue(field, value); return FieldMapBasedTag<VorbisComment>::setValue(field, value);
} }
} }

View File

@ -12,15 +12,26 @@ namespace Media {
class OggIterator; class OggIterator;
class VorbisComment; class VorbisComment;
class TAG_PARSER_EXPORT VorbisComment : public FieldMapBasedTag<VorbisCommentField, CaseInsensitiveStringComparer> /*!
* \brief Defines traits for the TagField implementation of the VorbisComment class.
*/
template <>
class TAG_PARSER_EXPORT FieldMapBasedTagTraits<VorbisComment>
{
public:
typedef VorbisComment implementationType;
typedef VorbisCommentField fieldType;
typedef CaseInsensitiveStringComparer compare;
};
class TAG_PARSER_EXPORT VorbisComment : public FieldMapBasedTag<VorbisComment>
{ {
public: public:
VorbisComment(); VorbisComment();
static constexpr TagType tagType = TagType::VorbisComment; static constexpr TagType tagType = TagType::VorbisComment;
TagType type() const; static constexpr const char *tagName = "Vorbis comment";
const char *typeName() const; static constexpr TagTextEncoding defaultTextEncoding = TagTextEncoding::Utf8;
TagTextEncoding proposedTextEncoding() const;
bool canEncodingBeUsed(TagTextEncoding encoding) const; bool canEncodingBeUsed(TagTextEncoding encoding) const;
const TagValue &value(KnownField field) const; const TagValue &value(KnownField field) const;
@ -49,21 +60,6 @@ private:
inline VorbisComment::VorbisComment() inline VorbisComment::VorbisComment()
{} {}
inline TagType VorbisComment::type() const
{
return TagType::VorbisComment;
}
inline const char *VorbisComment::typeName() const
{
return "Vorbis comment";
}
inline TagTextEncoding VorbisComment::proposedTextEncoding() const
{
return TagTextEncoding::Utf8;
}
inline bool VorbisComment::canEncodingBeUsed(TagTextEncoding encoding) const inline bool VorbisComment::canEncodingBeUsed(TagTextEncoding encoding) const
{ {
return encoding == TagTextEncoding::Utf8; return encoding == TagTextEncoding::Utf8;