Use static polymorphism in FieldMapBasedTag
This commit is contained in:
parent
138fa32f29
commit
0daabba17a
111
fieldbasedtag.h
111
fieldbasedtag.h
|
@ -24,18 +24,17 @@ class FieldMapBasedTagTraits
|
|||
* the tag fields using std::multimap.
|
||||
*
|
||||
* The FieldMapBasedTag class only provides the interface and common functionality.
|
||||
* It is meant to be subclassed.
|
||||
* It is meant to be subclassed using CRTP pattern.
|
||||
*
|
||||
* \tparam FieldType Specifies the class used to store the fields. Should be a subclass
|
||||
* of TagField.
|
||||
*
|
||||
* \tparam Compare Specifies the key comparsion function. Default is std::less.
|
||||
* \remarks This template class is intended to be subclassed using
|
||||
* with the "Curiously recurring template pattern".
|
||||
*/
|
||||
template <class ImplementationType>
|
||||
class FieldMapBasedTag : public Tag
|
||||
{
|
||||
public:
|
||||
friend class FieldMapBasedTagTraits<ImplementationType>;
|
||||
|
||||
public:
|
||||
typedef typename FieldMapBasedTagTraits<ImplementationType>::implementationType implementationType;
|
||||
typedef typename FieldMapBasedTagTraits<ImplementationType>::fieldType fieldType;
|
||||
typedef typename FieldMapBasedTagTraits<ImplementationType>::fieldType::identifierType identifierType;
|
||||
|
@ -46,29 +45,37 @@ public:
|
|||
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(const identifierType &id) const;
|
||||
const TagValue &value(KnownField field) const;
|
||||
std::vector<const TagValue *> values(const identifierType &id) const;
|
||||
std::vector<const TagValue *> values(KnownField field) const;
|
||||
virtual bool setValue(const identifierType &id, const TagValue &value); // FIXME: use static polymorphism
|
||||
bool setValue(const identifierType &id, const TagValue &value);
|
||||
bool setValue(KnownField field, const TagValue &value);
|
||||
bool setValues(const identifierType &id, const std::vector<TagValue> &values);
|
||||
bool setValues(KnownField field, const std::vector<TagValue> &values);
|
||||
bool hasField(KnownField field) const;
|
||||
virtual bool hasField(const identifierType &id) const; // FIXME: use static polymorphism
|
||||
bool hasField(const identifierType &id) const;
|
||||
void removeAllFields();
|
||||
const std::multimap<identifierType, fieldType, compare> &fields() const;
|
||||
std::multimap<identifierType, fieldType, compare> &fields();
|
||||
unsigned int fieldCount() const;
|
||||
virtual identifierType fieldId(KnownField value) const = 0; // FIXME: use static polymorphism
|
||||
virtual KnownField knownField(const identifierType &id) const = 0; // FIXME: use static polymorphism
|
||||
identifierType fieldId(KnownField value) const;
|
||||
KnownField knownField(const identifierType &id) const;
|
||||
bool supportsField(KnownField field) const;
|
||||
using Tag::proposedDataType;
|
||||
virtual TagDataType proposedDataType(const identifierType &id) const; // FIXME: use static polymorphism
|
||||
TagDataType proposedDataType(const identifierType &id) const;
|
||||
int insertFields(const FieldMapBasedTag<ImplementationType> &from, bool overwrite);
|
||||
unsigned int insertValues(const Tag &from, bool overwrite);
|
||||
void ensureTextValuesAreProperlyEncoded();
|
||||
|
||||
protected:
|
||||
const TagValue &internallyGetValue(const identifierType &id) const;
|
||||
bool internallySetValue(const identifierType &id, const TagValue &value);
|
||||
bool internallyHasField(const identifierType &id) const;
|
||||
// no default implementation: identifierType internallyGetFieldId(KnownField field) const;
|
||||
// no default implementation: KnownField internallyGetKnownField(const identifierType &id) const;
|
||||
TagDataType internallyGetProposedDataType(const identifierType &id) const;
|
||||
|
||||
private:
|
||||
std::multimap<identifierType, fieldType, compare> m_fields;
|
||||
};
|
||||
|
@ -112,6 +119,17 @@ TagTextEncoding FieldMapBasedTag<ImplementationType>::proposedTextEncoding() con
|
|||
return ImplementationType::defaultTextEncoding;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Default implementation for value().
|
||||
* \remarks Shadow in subclass to provide custom implementation.
|
||||
*/
|
||||
template<class ImplementationType>
|
||||
const TagValue &FieldMapBasedTag<ImplementationType>::internallyGetValue(const identifierType &id) const
|
||||
{
|
||||
auto i = m_fields.find(id);
|
||||
return i != m_fields.end() ? i->second.value() : TagValue::empty();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the value of the field with the specified \a id.
|
||||
* \sa Tag::value()
|
||||
|
@ -119,8 +137,7 @@ TagTextEncoding FieldMapBasedTag<ImplementationType>::proposedTextEncoding() con
|
|||
template <class ImplementationType>
|
||||
inline const TagValue &FieldMapBasedTag<ImplementationType>::value(const identifierType &id) const
|
||||
{
|
||||
auto i = m_fields.find(id);
|
||||
return i != m_fields.end() ? i->second.value() : TagValue::empty();
|
||||
return static_cast<const ImplementationType *>(this)->internallyGetValue(id);
|
||||
}
|
||||
|
||||
template <class ImplementationType>
|
||||
|
@ -159,11 +176,11 @@ inline bool FieldMapBasedTag<ImplementationType>::setValue(KnownField field, con
|
|||
}
|
||||
|
||||
/*!
|
||||
* \brief Assigns the given \a value to the field with the specified \a id.
|
||||
* \sa Tag::setValue()
|
||||
* \brief Default implementation for setValue().
|
||||
* \remarks Shadow in subclass to provide custom implementation.
|
||||
*/
|
||||
template <class ImplementationType>
|
||||
bool FieldMapBasedTag<ImplementationType>::setValue(const identifierType &id, const Media::TagValue &value)
|
||||
template<class ImplementationType>
|
||||
bool FieldMapBasedTag<ImplementationType>::internallySetValue(const identifierType &id, const TagValue &value)
|
||||
{
|
||||
auto i = m_fields.find(id);
|
||||
if(i != m_fields.end()) { // field already exists -> set its value
|
||||
|
@ -176,6 +193,16 @@ bool FieldMapBasedTag<ImplementationType>::setValue(const identifierType &id, co
|
|||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Assigns the given \a value to the field with the specified \a id.
|
||||
* \sa Tag::setValue()
|
||||
*/
|
||||
template <class ImplementationType>
|
||||
bool FieldMapBasedTag<ImplementationType>::setValue(const identifierType &id, const Media::TagValue &value)
|
||||
{
|
||||
return static_cast<ImplementationType *>(this)->internallySetValue(id, value);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Assigns the given \a values to the field with the specified \a id.
|
||||
* \remarks There might me more than one value assigned to an \a id. Whereas setValue() only alters the first value, this
|
||||
|
@ -225,10 +252,11 @@ inline bool FieldMapBasedTag<ImplementationType>::hasField(KnownField field) con
|
|||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns an indication whether the field with the specified \a id is present.
|
||||
* \brief Default implementation for hasField().
|
||||
* \remarks Shadow in subclass to provide custom implementation.
|
||||
*/
|
||||
template <class ImplementationType>
|
||||
inline bool FieldMapBasedTag<ImplementationType>::hasField(const identifierType &id) const
|
||||
template<class ImplementationType>
|
||||
bool FieldMapBasedTag<ImplementationType>::internallyHasField(const identifierType &id) const
|
||||
{
|
||||
for (auto range = m_fields.equal_range(id); range.first != range.second; ++range.first) {
|
||||
if(!range.first->second.value().isEmpty()) {
|
||||
|
@ -238,6 +266,15 @@ inline bool FieldMapBasedTag<ImplementationType>::hasField(const identifierType
|
|||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns an indication whether the field with the specified \a id is present.
|
||||
*/
|
||||
template <class ImplementationType>
|
||||
inline bool FieldMapBasedTag<ImplementationType>::hasField(const identifierType &id) const
|
||||
{
|
||||
return static_cast<const ImplementationType *>(this)->internallyHasField(id);
|
||||
}
|
||||
|
||||
template <class ImplementationType>
|
||||
inline void FieldMapBasedTag<ImplementationType>::removeAllFields()
|
||||
{
|
||||
|
@ -274,6 +311,26 @@ unsigned int FieldMapBasedTag<ImplementationType>::fieldCount() const
|
|||
return count;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the field ID for the specified \a value.
|
||||
* \remarks Must be implemented in internallyGetFieldId() when creating subclass.
|
||||
*/
|
||||
template<class ImplementationType>
|
||||
inline typename FieldMapBasedTag<ImplementationType>::identifierType FieldMapBasedTag<ImplementationType>::fieldId(KnownField value) const
|
||||
{
|
||||
return static_cast<const ImplementationType *>(this)->internallyGetFieldId(value);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the KnownField for the specified \a id.
|
||||
* \remarks Must be implemented in internallyGetKnownField() when creating subclass.
|
||||
*/
|
||||
template<class ImplementationType>
|
||||
inline KnownField FieldMapBasedTag<ImplementationType>::knownField(const identifierType &id) const
|
||||
{
|
||||
return static_cast<FieldMapBasedTag<ImplementationType> *>(this)->internallyGetKnownField(id);
|
||||
}
|
||||
|
||||
template <class ImplementationType>
|
||||
inline bool FieldMapBasedTag<ImplementationType>::supportsField(KnownField field) const
|
||||
{
|
||||
|
@ -281,13 +338,23 @@ inline bool FieldMapBasedTag<ImplementationType>::supportsField(KnownField field
|
|||
return fieldId(field) != def;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Default implementation for proposedDataType().
|
||||
* \remarks Shadow in subclass to provide custom implementation.
|
||||
*/
|
||||
template<class ImplementationType>
|
||||
inline TagDataType FieldMapBasedTag<ImplementationType>::internallyGetProposedDataType(const identifierType &id) const
|
||||
{
|
||||
return Tag::proposedDataType(knownField(id));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the proposed data type for the field with the specified \a id.
|
||||
*/
|
||||
template <class ImplementationType>
|
||||
inline TagDataType FieldMapBasedTag<ImplementationType>::proposedDataType(const identifierType &id) const
|
||||
{
|
||||
return Tag::proposedDataType(knownField(id));
|
||||
return static_cast<ImplementationType *>(this)->determineProposedDataType(id);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
@ -108,8 +108,9 @@ class FileElementTraits
|
|||
* \class Media::GenericFileElement
|
||||
* \brief The GenericFileElement class helps to parse binary files which consist
|
||||
* of an arboreal element strucutre.
|
||||
*
|
||||
* \tparam ImplementationType Specifies the type of the actual implementation.
|
||||
* \remarks This template class is intended to be subclassed using
|
||||
* with the "Curiously recurring template pattern".
|
||||
*/
|
||||
template <class ImplementationType>
|
||||
class TAG_PARSER_EXPORT GenericFileElement : public StatusProvider
|
||||
|
|
|
@ -25,7 +25,8 @@ class TagFieldTraits
|
|||
* might be assigned as well. The usage of the type info depends on the
|
||||
* particular tag implementation.
|
||||
*
|
||||
* \remarks This template class is intended to be used
|
||||
* \tparam ImplementationType Specifies the type of the actual implementation.
|
||||
* \remarks This template class is intended to be subclassed using
|
||||
* with the "Curiously recurring template pattern".
|
||||
*/
|
||||
template <class ImplementationType>
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace Media {
|
|||
* \brief Implementation of Media::Tag for ID3v2 tags.
|
||||
*/
|
||||
|
||||
uint32 Id3v2Tag::fieldId(KnownField field) const
|
||||
Id3v2Tag::identifierType Id3v2Tag::internallyGetFieldId(KnownField field) const
|
||||
{
|
||||
using namespace Id3v2FrameIds;
|
||||
if(m_majorVersion >= 3) {
|
||||
|
@ -78,7 +78,7 @@ uint32 Id3v2Tag::fieldId(KnownField field) const
|
|||
return 0;
|
||||
}
|
||||
|
||||
KnownField Id3v2Tag::knownField(const uint32 &id) const
|
||||
KnownField Id3v2Tag::internallyGetKnownField(const identifierType &id) const
|
||||
{
|
||||
using namespace Id3v2FrameIds;
|
||||
switch(id) {
|
||||
|
@ -125,7 +125,7 @@ KnownField Id3v2Tag::knownField(const uint32 &id) const
|
|||
}
|
||||
}
|
||||
|
||||
TagDataType Id3v2Tag::proposedDataType(const uint32 &id) const
|
||||
TagDataType Id3v2Tag::internallyGetProposedDataType(const uint32 &id) const
|
||||
{
|
||||
using namespace Id3v2FrameIds;
|
||||
switch(id) {
|
||||
|
|
|
@ -66,6 +66,8 @@ public:
|
|||
|
||||
class TAG_PARSER_EXPORT Id3v2Tag : public FieldMapBasedTag<Id3v2Tag>
|
||||
{
|
||||
friend class FieldMapBasedTag<Id3v2Tag>;
|
||||
|
||||
public:
|
||||
Id3v2Tag();
|
||||
|
||||
|
@ -74,11 +76,6 @@ public:
|
|||
static constexpr TagTextEncoding defaultTextEncoding = TagTextEncoding::Utf16LittleEndian;
|
||||
TagTextEncoding proposedTextEncoding() const;
|
||||
bool canEncodingBeUsed(TagTextEncoding encoding) const;
|
||||
uint32 fieldId(KnownField value) const;
|
||||
KnownField knownField(const uint32 &id) const;
|
||||
TagDataType proposedDataType(const uint32 &id) const;
|
||||
using FieldMapBasedTag<Id3v2Tag>::value;
|
||||
using FieldMapBasedTag<Id3v2Tag>::setValue;
|
||||
bool supportsDescription(KnownField field) const;
|
||||
bool supportsMimeType(KnownField field) const;
|
||||
|
||||
|
@ -98,6 +95,11 @@ public:
|
|||
uint32 extendedHeaderSize() const;
|
||||
uint32 paddingSize() const;
|
||||
|
||||
protected:
|
||||
identifierType internallyGetFieldId(KnownField field) const;
|
||||
KnownField internallyGetKnownField(const identifierType &id) const;
|
||||
TagDataType internallyGetProposedDataType(const uint32 &id) const;
|
||||
|
||||
private:
|
||||
byte m_majorVersion;
|
||||
byte m_revisionVersion;
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace Media {
|
|||
* \brief Implementation of Media::Tag for the Matroska container.
|
||||
*/
|
||||
|
||||
std::string MatroskaTag::fieldId(KnownField field) const
|
||||
MatroskaTag::identifierType MatroskaTag::internallyGetFieldId(KnownField field) const
|
||||
{
|
||||
using namespace MatroskaTagIds;
|
||||
switch(field) {
|
||||
|
@ -45,7 +45,7 @@ std::string MatroskaTag::fieldId(KnownField field) const
|
|||
}
|
||||
}
|
||||
|
||||
KnownField MatroskaTag::knownField(const std::string &id) const
|
||||
KnownField MatroskaTag::internallyGetKnownField(const identifierType &id) const
|
||||
{
|
||||
using namespace MatroskaTagIds;
|
||||
static const map<string, KnownField> map({
|
||||
|
|
|
@ -61,6 +61,8 @@ public:
|
|||
|
||||
class TAG_PARSER_EXPORT MatroskaTag : public FieldMapBasedTag<MatroskaTag>
|
||||
{
|
||||
friend class FieldMapBasedTag<MatroskaTag>;
|
||||
|
||||
public:
|
||||
MatroskaTag();
|
||||
|
||||
|
@ -71,13 +73,14 @@ public:
|
|||
bool supportsTarget() const;
|
||||
TagTargetLevel targetLevel() const;
|
||||
|
||||
std::string fieldId(KnownField field) const;
|
||||
KnownField knownField(const std::string &id) const;
|
||||
|
||||
void parse(EbmlElement &tagElement);
|
||||
MatroskaTagMaker prepareMaking();
|
||||
void make(std::ostream &stream);
|
||||
|
||||
protected:
|
||||
identifierType internallyGetFieldId(KnownField field) const;
|
||||
KnownField internallyGetKnownField(const identifierType &id) const;
|
||||
|
||||
private:
|
||||
void parseTargets(EbmlElement &targetsElement);
|
||||
};
|
||||
|
|
|
@ -119,7 +119,7 @@ const TagValue &Mp4Tag::value(const string mean, const string name) const
|
|||
return (this->*static_cast<const TagValue &(Mp4Tag::*)(const string &, const string &) const>(&Mp4Tag::value))(mean, name);
|
||||
}
|
||||
|
||||
uint32 Mp4Tag::fieldId(KnownField field) const
|
||||
Mp4Tag::identifierType Mp4Tag::internallyGetFieldId(KnownField field) const
|
||||
{
|
||||
using namespace Mp4TagAtomIds;
|
||||
switch(field) {
|
||||
|
@ -146,7 +146,7 @@ uint32 Mp4Tag::fieldId(KnownField field) const
|
|||
}
|
||||
}
|
||||
|
||||
KnownField Mp4Tag::knownField(const uint32 &id) const
|
||||
KnownField Mp4Tag::internallyGetKnownField(const identifierType &id) const
|
||||
{
|
||||
using namespace Mp4TagAtomIds;
|
||||
switch(id) {
|
||||
|
|
|
@ -101,6 +101,8 @@ public:
|
|||
|
||||
class TAG_PARSER_EXPORT Mp4Tag : public FieldMapBasedTag<Mp4Tag>
|
||||
{
|
||||
friend class FieldMapBasedTag<Mp4Tag>;
|
||||
|
||||
public:
|
||||
Mp4Tag();
|
||||
|
||||
|
@ -109,8 +111,6 @@ public:
|
|||
static constexpr TagTextEncoding defaultTextEncoding = TagTextEncoding::Utf8;
|
||||
bool canEncodingBeUsed(TagTextEncoding encoding) const;
|
||||
|
||||
uint32 fieldId(KnownField field) const;
|
||||
KnownField knownField(const uint32 &id) const;
|
||||
bool supportsField(KnownField field) const;
|
||||
using FieldMapBasedTag<Mp4Tag>::value;
|
||||
const TagValue &value(KnownField value) const;
|
||||
|
@ -136,6 +136,11 @@ public:
|
|||
void parse(Mp4Atom &metaAtom);
|
||||
Mp4TagMaker prepareMaking();
|
||||
void make(std::ostream &stream);
|
||||
|
||||
protected:
|
||||
identifierType internallyGetFieldId(KnownField field) const;
|
||||
KnownField internallyGetKnownField(const identifierType &id) const;
|
||||
|
||||
};
|
||||
|
||||
/*!
|
||||
|
|
|
@ -44,7 +44,7 @@ bool VorbisComment::setValue(KnownField field, const TagValue &value)
|
|||
}
|
||||
}
|
||||
|
||||
string VorbisComment::fieldId(KnownField field) const
|
||||
VorbisComment::identifierType VorbisComment::internallyGetFieldId(KnownField field) const
|
||||
{
|
||||
using namespace VorbisCommentIds;
|
||||
switch(field) {
|
||||
|
@ -70,7 +70,7 @@ string VorbisComment::fieldId(KnownField field) const
|
|||
}
|
||||
}
|
||||
|
||||
KnownField VorbisComment::knownField(const string &id) const
|
||||
KnownField VorbisComment::internallyGetKnownField(const identifierType &id) const
|
||||
{
|
||||
using namespace VorbisCommentIds;
|
||||
static const map<string, KnownField> fieldMap({
|
||||
|
|
|
@ -26,6 +26,8 @@ public:
|
|||
|
||||
class TAG_PARSER_EXPORT VorbisComment : public FieldMapBasedTag<VorbisComment>
|
||||
{
|
||||
friend class FieldMapBasedTag<VorbisComment>;
|
||||
|
||||
public:
|
||||
VorbisComment();
|
||||
|
||||
|
@ -34,10 +36,10 @@ public:
|
|||
static constexpr TagTextEncoding defaultTextEncoding = TagTextEncoding::Utf8;
|
||||
bool canEncodingBeUsed(TagTextEncoding encoding) const;
|
||||
|
||||
using FieldMapBasedTag<VorbisComment>::value;
|
||||
const TagValue &value(KnownField field) const;
|
||||
using FieldMapBasedTag<VorbisComment>::setValue;
|
||||
bool setValue(KnownField field, const TagValue &value);
|
||||
std::string fieldId(KnownField field) const;
|
||||
KnownField knownField(const std::string &id) const;
|
||||
|
||||
void parse(OggIterator &iterator, VorbisCommentFlags flags = VorbisCommentFlags::None);
|
||||
void parse(std::istream &stream, uint64 maxSize, VorbisCommentFlags flags = VorbisCommentFlags::None);
|
||||
|
@ -46,6 +48,10 @@ public:
|
|||
const TagValue &vendor() const;
|
||||
void setVendor(const TagValue &vendor);
|
||||
|
||||
protected:
|
||||
identifierType internallyGetFieldId(KnownField field) const;
|
||||
KnownField internallyGetKnownField(const identifierType &id) const;
|
||||
|
||||
private:
|
||||
template<class StreamType>
|
||||
void internalParse(StreamType &stream, uint64 maxSize, VorbisCommentFlags flags);
|
||||
|
|
Loading…
Reference in New Issue